1 /* Copyright (C) 2007 Free Software Foundation, Inc.
3 This file is part of GCC.
5 GCC is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2, or (at your option) any later
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
19 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 You should have received a copy of the GNU General Public License
25 along with GCC; see the file COPYING. If not, write to the Free
26 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "bid_internal.h"
31 #include "bid128_2_str.h"
32 #include "bid128_2_str_macros.h"
34 #define MAX_FORMAT_DIGITS 16
35 #define DECIMAL_EXPONENT_BIAS 398
36 #define MAX_DECIMAL_EXPONENT 767
38 #if DECIMAL_CALL_BY_REFERENCE
41 bid64_to_string (char *ps, UINT64 * px
42 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
47 bid64_to_string (char *ps, UINT64 x
48 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
50 // the destination string (pointed to by ps) must be pre-allocated
51 UINT64 sign_x, coefficient_x, D, ER10;
52 int istart, exponent_x, j, digits_x, bin_expon_cx;
54 UINT32 MiDi[12], *ptr;
55 UINT64 HI_18Dig, LO_18Dig, Tmp;
56 char *c_ptr_start, *c_ptr;
57 int midi_ind, k_lcv, len;
58 unsigned int save_fpsf;
60 #if DECIMAL_CALL_BY_REFERENCE
64 save_fpsf = *pfpsf; // place holder only
65 // unpack arguments, check for NaN or Infinity
66 if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) {
67 // x is Inf. or NaN or 0
70 if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
71 if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
72 ps[0] = (sign_x) ? '-' : '+';
73 ps[1] = ((x & MASK_SNAN) == MASK_SNAN)? 'S':'Q';
81 ps[0] = (sign_x) ? '-' : '+';
100 exponent_x = -exponent_x;
105 // get decimal digits in coefficient_x
106 tempx.d = (float) exponent_x;
107 bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
108 digits_x = estimate_decimal_digits[bin_expon_cx];
109 if ((UINT64)exponent_x >= power10_table_128[digits_x].w[0])
112 j = istart + digits_x - 1;
118 while (exponent_x > 9) {
119 D = (UINT64) exponent_x *ER10;
121 exponent_x = exponent_x - (D << 1) - (D << 3);
123 ps[j--] = '0' + (char) exponent_x;
126 ps[j] = '0' + (char) exponent_x;
135 // convert expon, coeff to ASCII
136 exponent_x -= DECIMAL_EXPONENT_BIAS;
145 // if zero or non-canonical, set coefficient to '0'
146 if ((coefficient_x > 9999999999999999ull) || // non-canonical
147 ((coefficient_x == 0)) // significand is zero
151 /* ****************************************************
152 This takes a bid coefficient in C1.w[1],C1.w[0]
153 and put the converted character sequence at location
154 starting at &(str[k]). The function returns the number
155 of MiDi returned. Note that the character sequence
156 does not have leading zeros EXCEPT when the input is of
157 zero value. It will then output 1 character '0'
158 The algorithm essentailly tries first to get a sequence of
159 Millenial Digits "MiDi" and then uses table lookup to get the
160 character strings of these MiDis.
161 **************************************************** */
162 /* Algorithm first decompose possibly 34 digits in hi and lo
163 18 digits. (The high can have at most 16 digits). It then
164 uses macro that handle 18 digit portions.
165 The first step is to get hi and lo such that
166 2^(64) C1.w[1] + C1.w[0] = hi * 10^18 + lo, 0 <= lo < 10^18.
167 We use a table lookup method to obtain the hi and lo 18 digits.
168 [C1.w[1],C1.w[0]] = c_8 2^(107) + c_7 2^(101) + ... + c_0 2^(59) + d
169 where 0 <= d < 2^59 and each c_j has 6 bits. Because d fits in
170 18 digits, we set hi = 0, and lo = d to begin with.
171 We then retrieve from a table, for j = 0, 1, ..., 8
172 that gives us A and B where c_j 2^(59+6j) = A * 10^18 + B.
173 hi += A ; lo += B; After each accumulation into lo, we normalize
174 immediately. So at the end, we have the decomposition as we need. */
176 Tmp = coefficient_x >> 59;
177 LO_18Dig = (coefficient_x << 5) >> 5;
182 midi_ind = (int) (Tmp & 0x000000000000003FLL);
185 HI_18Dig += mod10_18_tbl[k_lcv][midi_ind++];
186 LO_18Dig += mod10_18_tbl[k_lcv++][midi_ind];
187 __L0_Normalize_10to18 (HI_18Dig, LO_18Dig);
191 __L1_Split_MiDi_6_Lead (LO_18Dig, ptr);
193 c_ptr_start = &(ps[istart]);
196 /* now convert the MiDi into character strings */
197 __L0_MiDi2Str_Lead (MiDi[0], c_ptr);
198 for (k_lcv = 1; k_lcv < len; k_lcv++) {
199 __L0_MiDi2Str (MiDi[k_lcv], c_ptr);
201 istart = istart + (c_ptr - c_ptr_start);
206 if (exponent_x < 0) {
208 exponent_x = -exponent_x;
213 // get decimal digits in coefficient_x
214 tempx.d = (float) exponent_x;
215 bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
216 digits_x = estimate_decimal_digits[bin_expon_cx];
217 if ((UINT64)exponent_x >= power10_table_128[digits_x].w[0])
220 j = istart + digits_x - 1;
226 while (exponent_x > 9) {
227 D = (UINT64) exponent_x *ER10;
229 exponent_x = exponent_x - (D << 1) - (D << 3);
231 ps[j--] = '0' + (char) exponent_x;
234 ps[j] = '0' + (char) exponent_x;
246 #if DECIMAL_CALL_BY_REFERENCE
248 bid64_from_string (UINT64 * pres, char *ps
249 _RND_MODE_PARAM _EXC_FLAGS_PARAM
250 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
253 bid64_from_string (char *ps
254 _RND_MODE_PARAM _EXC_FLAGS_PARAM
255 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
257 UINT64 sign_x, coefficient_x = 0, rounded = 0, res;
258 int expon_x = 0, sgn_expon, ndigits, add_expon = 0, midpoint =
260 int dec_expon_scale = 0, right_radix_leading_zeros = 0, rdx_pt_enc =
264 unsigned int save_fpsf;
266 #if DECIMAL_CALL_BY_REFERENCE
267 #if !DECIMAL_GLOBAL_ROUNDING
268 _IDEC_round rnd_mode = *prnd_mode;
272 save_fpsf = *pfpsf; // place holder only
273 // eliminate leading whitespace
274 while (((*ps == ' ') || (*ps == '\t')) && (*ps))
277 // get first non-whitespace character
280 // detect special cases (INF or NaN)
281 if (!c || (c != '.' && c != '-' && c != '+' && (c < '0' || c > '9'))) {
283 if ((tolower_macro (ps[0]) == 'i' && tolower_macro (ps[1]) == 'n' &&
284 tolower_macro (ps[2]) == 'f') && (!ps[3] ||
285 (tolower_macro (ps[3]) == 'i' &&
286 tolower_macro (ps[4]) == 'n' && tolower_macro (ps[5]) == 'i' &&
287 tolower_macro (ps[6]) == 't' && tolower_macro (ps[7]) == 'y' &&
289 res = 0x7800000000000000ull;
293 if (tolower_macro (ps[0]) == 's' && tolower_macro (ps[1]) == 'n' &&
294 tolower_macro (ps[2]) == 'a' && tolower_macro (ps[3]) == 'n') {
295 // case insensitive check for snan
296 res = 0x7e00000000000000ull;
300 res = 0x7c00000000000000ull;
304 // detect +INF or -INF
305 if ((tolower_macro (ps[1]) == 'i' && tolower_macro (ps[2]) == 'n' &&
306 tolower_macro (ps[3]) == 'f') && (!ps[4] ||
307 (tolower_macro (ps[4]) == 'i' && tolower_macro (ps[5]) == 'n' &&
308 tolower_macro (ps[6]) == 'i' && tolower_macro (ps[7]) == 't' &&
309 tolower_macro (ps[8]) == 'y' && !ps[9]))) {
311 res = 0x7800000000000000ull;
313 res = 0xf800000000000000ull;
315 res = 0x7c00000000000000ull;
318 // if +sNaN, +SNaN, -sNaN, or -SNaN
319 if (tolower_macro (ps[1]) == 's' && tolower_macro (ps[2]) == 'n'
320 && tolower_macro (ps[3]) == 'a' && tolower_macro (ps[4]) == 'n') {
322 res = 0xfe00000000000000ull;
324 res = 0x7e00000000000000ull;
329 sign_x = 0x8000000000000000ull;
333 // get next character if leading +/- sign
334 if (c == '-' || c == '+') {
338 // if c isn't a decimal point or a decimal digit, return NaN
339 if (c != '.' && (c < '0' || c > '9')) {
341 res = 0x7c00000000000000ull | sign_x;
347 // detect zero (and eliminate/ignore leading zeros)
348 if (*(ps) == '0' || *(ps) == '.') {
354 // if all numbers are zeros (with possibly 1 radix point, the number is zero
355 // should catch cases such as: 000.0
358 // for numbers such as 0.0000000000000000000000000000000000001001,
359 // we want to count the leading zeros
361 right_radix_leading_zeros++;
363 // if this character is a radix point, make sure we haven't already
366 if (rdx_pt_enc == 0) {
368 // if this is the first radix point, and the next character is NULL,
372 ((UINT64) (398 - right_radix_leading_zeros) << 53) |
378 // if 2 radix points, return NaN
379 res = 0x7c00000000000000ull | sign_x;
383 //pres->w[1] = 0x3040000000000000ull | sign_x;
385 ((UINT64) (398 - right_radix_leading_zeros) << 53) | sign_x;
394 while ((c >= '0' && c <= '9') || c == '.') {
398 res = 0x7c00000000000000ull | sign_x;
406 dec_expon_scale += rdx_pt_enc;
410 coefficient_x = (coefficient_x << 1) + (coefficient_x << 3);
411 coefficient_x += (UINT64) (c - '0');
412 } else if (ndigits == 17) {
413 // coefficient rounding
415 case ROUNDING_TO_NEAREST:
416 midpoint = (c == '5' && !(coefficient_x & 1)) ? 1 : 0;
417 // if coefficient is even and c is 5, prepare to round up if
418 // subsequent digit is nonzero
419 // if str[MAXDIG+1] > 5, we MUST round up
420 // if str[MAXDIG+1] == 5 and coefficient is ODD, ROUND UP!
421 if (c > '5' || (c == '5' && (coefficient_x & 1))) {
427 if(sign_x) { coefficient_x++; rounded_up=1; }
430 if(!sign_x) { coefficient_x++; rounded_up=1; }
432 case ROUNDING_TIES_AWAY:
433 if(c>='5') { coefficient_x++; rounded_up=1; }
436 if (coefficient_x == 10000000000000000ull) {
437 coefficient_x = 1000000000000000ull;
444 } else { // ndigits > 17
446 if (midpoint && c > '0') {
458 add_expon -= (dec_expon_scale + right_radix_leading_zeros);
462 fast_get_BID64_check_OF (sign_x,
463 add_expon + DECIMAL_EXPONENT_BIAS,
464 coefficient_x, 0, &fpsc);
468 if (c != 'E' && c != 'e') {
470 res = 0x7c00000000000000ull | sign_x;
475 sgn_expon = (c == '-') ? 1 : 0;
476 if (c == '-' || c == '+') {
480 if (!c || c < '0' || c > '9') {
482 res = 0x7c00000000000000ull | sign_x;
486 while (c >= '0' && c <= '9') {
487 expon_x = (expon_x << 1) + (expon_x << 3);
488 expon_x += (int) (c - '0');
496 res = 0x7c00000000000000ull | sign_x;
503 expon_x += add_expon + DECIMAL_EXPONENT_BIAS;
510 get_BID64_UF (sign_x, expon_x, coefficient_x, rounded, rnd_mode,
514 res = get_BID64 (sign_x, expon_x, coefficient_x, rnd_mode, &fpsc);