2008-01-10 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libgcc / config / libbid / bid_string.c
blobe339dd2023465b96418f35a37665149cdc6fb199
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
8 version.
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
17 executable.)
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
22 for more details.
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
27 02110-1301, USA. */
29 #include <ctype.h>
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
40 void
41 __bid64_to_string (char *ps, UINT64 * px
42 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
43 _EXC_INFO_PARAM) {
44 UINT64 x;
45 #else
47 void
48 __bid64_to_string (char *ps, UINT64 x
49 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
50 _EXC_INFO_PARAM) {
51 #endif
52 // the destination string (pointed to by ps) must be pre-allocated
53 UINT64 sign_x, coefficient_x, D, ER10;
54 int istart, exponent_x, j, digits_x, bin_expon_cx;
55 int_float tempx;
56 UINT32 MiDi[12], *ptr;
57 UINT64 HI_18Dig, LO_18Dig, Tmp;
58 char *c_ptr_start, *c_ptr;
59 int midi_ind, k_lcv, len;
61 #if DECIMAL_CALL_BY_REFERENCE
62 #if !DECIMAL_GLOBAL_ROUNDING
63 _IDEC_round rnd_mode = *prnd_mode;
64 #endif
65 x = *px;
66 #endif
68 // unpack arguments, check for NaN or Infinity
69 if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) {
70 // x is Inf. or NaN or 0
72 // Inf or NaN?
73 if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
74 if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
75 ps[0] = 'N';
76 ps[1] = 'a';
77 ps[2] = 'N';
78 ps[3] = 0;
79 return;
81 // x is Inf
82 ps[0] = (sign_x) ? '-' : '+';
83 ps[1] = 'I';
84 ps[2] = 'n';
85 ps[3] = 'f';
86 ps[4] = 0;
87 return;
89 // 0
90 istart = 0;
91 if (sign_x) {
92 ps[istart++] = '-';
95 ps[istart++] = '0';
96 ps[istart++] = 'E';
98 exponent_x -= 398;
99 if (exponent_x < 0) {
100 ps[istart++] = '-';
101 exponent_x = -exponent_x;
102 } else
103 ps[istart++] = '+';
105 if (exponent_x) {
106 // get decimal digits in coefficient_x
107 tempx.d = (float) exponent_x;
108 bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
109 digits_x = __bid_estimate_decimal_digits[bin_expon_cx];
110 if ((UINT64)exponent_x >= __bid_power10_table_128[digits_x].w[0])
111 digits_x++;
113 j = istart + digits_x - 1;
114 istart = j + 1;
116 // 2^32/10
117 ER10 = 0x1999999a;
119 while (exponent_x > 9) {
120 D = (UINT64) exponent_x *ER10;
121 D >>= 32;
122 exponent_x = exponent_x - (D << 1) - (D << 3);
124 ps[j--] = '0' + (char) exponent_x;
125 exponent_x = D;
127 ps[j] = '0' + (char) exponent_x;
128 } else {
129 ps[istart++] = '0';
132 ps[istart] = 0;
134 return;
136 // convert expon, coeff to ASCII
137 exponent_x -= DECIMAL_EXPONENT_BIAS;
139 ER10 = 0x1999999a;
141 istart = 0;
142 if (sign_x) {
143 ps[0] = '-';
144 istart = 1;
146 // if zero or non-canonical, set coefficient to '0'
147 if ((coefficient_x > 9999999999999999ull) || // non-canonical
148 ((coefficient_x == 0)) // significand is zero
150 ps[istart++] = '0';
151 } else {
152 /* ****************************************************
153 This takes a bid coefficient in C1.w[1],C1.w[0]
154 and put the converted character sequence at location
155 starting at &(str[k]). The function returns the number
156 of MiDi returned. Note that the character sequence
157 does not have leading zeros EXCEPT when the input is of
158 zero value. It will then output 1 character '0'
159 The algorithm essentailly tries first to get a sequence of
160 Millenial Digits "MiDi" and then uses table lookup to get the
161 character strings of these MiDis.
162 **************************************************** */
163 /* Algorithm first decompose possibly 34 digits in hi and lo
164 18 digits. (The high can have at most 16 digits). It then
165 uses macro that handle 18 digit portions.
166 The first step is to get hi and lo such that
167 2^(64) C1.w[1] + C1.w[0] = hi * 10^18 + lo, 0 <= lo < 10^18.
168 We use a table lookup method to obtain the hi and lo 18 digits.
169 [C1.w[1],C1.w[0]] = c_8 2^(107) + c_7 2^(101) + ... + c_0 2^(59) + d
170 where 0 <= d < 2^59 and each c_j has 6 bits. Because d fits in
171 18 digits, we set hi = 0, and lo = d to begin with.
172 We then retrieve from a table, for j = 0, 1, ..., 8
173 that gives us A and B where c_j 2^(59+6j) = A * 10^18 + B.
174 hi += A ; lo += B; After each accumulation into lo, we normalize
175 immediately. So at the end, we have the decomposition as we need. */
177 Tmp = coefficient_x >> 59;
178 LO_18Dig = (coefficient_x << 5) >> 5;
179 HI_18Dig = 0;
180 k_lcv = 0;
182 while (Tmp) {
183 midi_ind = (int) (Tmp & 0x000000000000003FLL);
184 midi_ind <<= 1;
185 Tmp >>= 6;
186 HI_18Dig += __bid_mod10_18_tbl[k_lcv][midi_ind++];
187 LO_18Dig += __bid_mod10_18_tbl[k_lcv++][midi_ind];
188 __L0_Normalize_10to18 (HI_18Dig, LO_18Dig);
191 ptr = MiDi;
192 __L1_Split_MiDi_6_Lead (LO_18Dig, ptr);
193 len = ptr - MiDi;
194 c_ptr_start = &(ps[istart]);
195 c_ptr = c_ptr_start;
197 /* now convert the MiDi into character strings */
198 __L0_MiDi2Str_Lead (MiDi[0], c_ptr);
199 for (k_lcv = 1; k_lcv < len; k_lcv++) {
200 __L0_MiDi2Str (MiDi[k_lcv], c_ptr);
202 istart = istart + (c_ptr - c_ptr_start);
205 ps[istart++] = 'E';
207 if (exponent_x < 0) {
208 ps[istart++] = '-';
209 exponent_x = -exponent_x;
210 } else
211 ps[istart++] = '+';
213 if (exponent_x) {
214 // get decimal digits in coefficient_x
215 tempx.d = (float) exponent_x;
216 bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
217 digits_x = __bid_estimate_decimal_digits[bin_expon_cx];
218 if ((UINT64)exponent_x >= __bid_power10_table_128[digits_x].w[0])
219 digits_x++;
221 j = istart + digits_x - 1;
222 istart = j + 1;
224 // 2^32/10
225 ER10 = 0x1999999a;
227 while (exponent_x > 9) {
228 D = (UINT64) exponent_x *ER10;
229 D >>= 32;
230 exponent_x = exponent_x - (D << 1) - (D << 3);
232 ps[j--] = '0' + (char) exponent_x;
233 exponent_x = D;
235 ps[j] = '0' + (char) exponent_x;
236 } else {
237 ps[istart++] = '0';
240 ps[istart] = 0;
242 return;
248 #if DECIMAL_CALL_BY_REFERENCE
250 void
251 __bid64_from_string (UINT64 * pres, char *ps
252 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
253 _EXC_INFO_PARAM) {
254 #else
256 UINT64
257 __bid64_from_string (char *ps
258 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
259 _EXC_INFO_PARAM) {
260 #endif
261 UINT64 sign_x, coefficient_x = 0, rounded = 0, res;
262 int expon_x = 0, sgn_expon, ndigits, add_expon = 0, midpoint =
263 0, rounded_up = 0;
264 int dec_expon_scale = 0, right_radix_leading_zeros = 0, rdx_pt_enc =
266 unsigned fpsc;
267 char c;
269 #if DECIMAL_CALL_BY_REFERENCE
270 #if !DECIMAL_GLOBAL_ROUNDING
271 _IDEC_round rnd_mode = *prnd_mode;
272 #endif
273 #endif
275 // eliminate leading whitespace
276 while (((*ps == ' ') || (*ps == '\t')) && (*ps))
277 ps++;
279 // get first non-whitespace character
280 c = *ps;
282 // detect special cases (INF or NaN)
283 if (!c || (c != '.' && c != '-' && c != '+' && (c < '0' || c > '9'))) {
284 // Infinity?
285 if ((tolower_macro (ps[0]) == 'i' && tolower_macro (ps[1]) == 'n' &&
286 tolower_macro (ps[2]) == 'f') && (!ps[3] ||
287 (tolower_macro (ps[3]) == 'i' &&
288 tolower_macro (ps[4]) == 'n' && tolower_macro (ps[5]) == 'i' &&
289 tolower_macro (ps[6]) == 't' && tolower_macro (ps[7]) == 'y' &&
290 !ps[8]))) {
291 res = 0x7800000000000000ull;
292 BID_RETURN (res);
294 // return sNaN
295 if (tolower_macro (ps[0]) == 's' && tolower_macro (ps[1]) == 'n' &&
296 tolower_macro (ps[2]) == 'a' && tolower_macro (ps[3]) == 'n') {
297 // case insensitive check for snan
298 res = 0x7e00000000000000ull;
299 BID_RETURN (res);
300 } else {
301 // return qNaN
302 res = 0x7c00000000000000ull;
303 BID_RETURN (res);
306 // detect +INF or -INF
307 if ((tolower_macro (ps[1]) == 'i' && tolower_macro (ps[2]) == 'n' &&
308 tolower_macro (ps[3]) == 'f') && (!ps[4] ||
309 (tolower_macro (ps[4]) == 'i' && tolower_macro (ps[5]) == 'n' &&
310 tolower_macro (ps[6]) == 'i' && tolower_macro (ps[7]) == 't' &&
311 tolower_macro (ps[8]) == 'y' && !ps[9]))) {
312 if (c == '+')
313 res = 0x7800000000000000ull;
314 else if (c == '-')
315 res = 0xf800000000000000ull;
316 else
317 res = 0x7c00000000000000ull;
318 BID_RETURN (res);
320 // if +sNaN, +SNaN, -sNaN, or -SNaN
321 if (tolower_macro (ps[1]) == 's' && tolower_macro (ps[2]) == 'n'
322 && tolower_macro (ps[3]) == 'a' && tolower_macro (ps[4]) == 'n') {
323 if (c == '-')
324 res = 0xfe00000000000000ull;
325 else
326 res = 0x7e00000000000000ull;
327 BID_RETURN (res);
329 // determine sign
330 if (c == '-')
331 sign_x = 0x8000000000000000ull;
332 else
333 sign_x = 0;
335 // get next character if leading +/- sign
336 if (c == '-' || c == '+') {
337 ps++;
338 c = *ps;
340 // if c isn't a decimal point or a decimal digit, return NaN
341 if (c != '.' && (c < '0' || c > '9')) {
342 // return NaN
343 res = 0x7c00000000000000ull | sign_x;
344 BID_RETURN (res);
347 rdx_pt_enc = 0;
349 // detect zero (and eliminate/ignore leading zeros)
350 if (*(ps) == '0' || *(ps) == '.') {
352 if (*(ps) == '.') {
353 rdx_pt_enc = 1;
354 ps++;
356 // if all numbers are zeros (with possibly 1 radix point, the number is zero
357 // should catch cases such as: 000.0
358 while (*ps == '0') {
359 ps++;
360 // for numbers such as 0.0000000000000000000000000000000000001001,
361 // we want to count the leading zeros
362 if (rdx_pt_enc) {
363 right_radix_leading_zeros++;
365 // if this character is a radix point, make sure we haven't already
366 // encountered one
367 if (*(ps) == '.') {
368 if (rdx_pt_enc == 0) {
369 rdx_pt_enc = 1;
370 // if this is the first radix point, and the next character is NULL,
371 // we have a zero
372 if (!*(ps + 1)) {
373 res =
374 ((UINT64) (398 - right_radix_leading_zeros) << 53) |
375 sign_x;
376 BID_RETURN (res);
378 ps = ps + 1;
379 } else {
380 // if 2 radix points, return NaN
381 res = 0x7c00000000000000ull | sign_x;
382 BID_RETURN (res);
384 } else if (!*(ps)) {
385 //pres->w[1] = 0x3040000000000000ull | sign_x;
386 res =
387 ((UINT64) (398 - right_radix_leading_zeros) << 53) | sign_x;
388 BID_RETURN (res);
393 c = *ps;
395 ndigits = 0;
396 while ((c >= '0' && c <= '9') || c == '.') {
397 if (c == '.') {
398 if (rdx_pt_enc) {
399 // return NaN
400 res = 0x7c00000000000000ull | sign_x;
401 BID_RETURN (res);
403 rdx_pt_enc = 1;
404 ps++;
405 c = *ps;
406 continue;
408 dec_expon_scale += rdx_pt_enc;
410 ndigits++;
411 if (ndigits <= 16) {
412 coefficient_x = (coefficient_x << 1) + (coefficient_x << 3);
413 coefficient_x += (UINT64) (c - '0');
414 } else if (ndigits == 17) {
415 // coefficient rounding
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))) {
422 coefficient_x++;
423 rounded_up = 1;
424 if (coefficient_x == 10000000000000000ull) {
425 coefficient_x = 1000000000000000ull;
426 add_expon = 1;
429 if (c > '0')
430 rounded = 1;
431 add_expon += 1;
432 } else { // ndigits > 17
433 add_expon++;
434 if (midpoint && c > '0') {
435 coefficient_x++;
436 midpoint = 0;
437 rounded_up = 1;
439 if (c > '0')
440 rounded = 1;
442 ps++;
443 c = *ps;
446 add_expon -= (dec_expon_scale + right_radix_leading_zeros);
448 if (!c) {
449 res =
450 fast_get_BID64_check_OF (sign_x,
451 add_expon + DECIMAL_EXPONENT_BIAS,
452 coefficient_x, 0, &fpsc);
453 BID_RETURN (res);
456 if (c != 'E' && c != 'e') {
457 // return NaN
458 res = 0x7c00000000000000ull | sign_x;
459 BID_RETURN (res);
461 ps++;
462 c = *ps;
463 sgn_expon = (c == '-') ? 1 : 0;
464 if (c == '-' || c == '+') {
465 ps++;
466 c = *ps;
468 if (!c || c < '0' || c > '9') {
469 // return NaN
470 res = 0x7c00000000000000ull | sign_x;
471 BID_RETURN (res);
474 while (c >= '0' && c <= '9') {
475 expon_x = (expon_x << 1) + (expon_x << 3);
476 expon_x += (int) (c - '0');
478 ps++;
479 c = *ps;
482 if (c) {
483 // return NaN
484 res = 0x7c00000000000000ull | sign_x;
485 BID_RETURN (res);
488 if (sgn_expon)
489 expon_x = -expon_x;
491 expon_x += add_expon + DECIMAL_EXPONENT_BIAS;
493 if (expon_x < 0) {
494 if (rounded_up)
495 coefficient_x--;
496 rnd_mode = 0;
497 res =
498 get_BID64_UF (sign_x, expon_x, coefficient_x, rounded, rnd_mode,
499 &fpsc);
500 BID_RETURN (res);
502 res = get_BID64 (sign_x, expon_x, coefficient_x, rnd_mode, &fpsc);
503 BID_RETURN (res);