OSDN Git Service

./:
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid_string.c
1 /* Copyright (C) 2007  Free Software Foundation, Inc.
2
3 This file is part of GCC.
4
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.
9
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.)
18
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.
23
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.  */
28
29 #include <ctype.h>
30 #include "bid_internal.h"
31 #include "bid128_2_str.h"
32 #include "bid128_2_str_macros.h"
33
34 #define MAX_FORMAT_DIGITS     16
35 #define DECIMAL_EXPONENT_BIAS 398
36 #define MAX_DECIMAL_EXPONENT  767
37
38 #if DECIMAL_CALL_BY_REFERENCE
39
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
46
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;
60
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
67
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
71
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;
80       }
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;
88     }
89     // 0
90     istart = 0;
91     if (sign_x) {
92       ps[istart++] = '-';
93     }
94
95     ps[istart++] = '0';
96     ps[istart++] = 'E';
97
98     exponent_x -= 398;
99     if (exponent_x < 0) {
100       ps[istart++] = '-';
101       exponent_x = -exponent_x;
102     } else
103       ps[istart++] = '+';
104
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++;
112
113       j = istart + digits_x - 1;
114       istart = j + 1;
115
116       // 2^32/10
117       ER10 = 0x1999999a;
118
119       while (exponent_x > 9) {
120         D = (UINT64) exponent_x *ER10;
121         D >>= 32;
122         exponent_x = exponent_x - (D << 1) - (D << 3);
123
124         ps[j--] = '0' + (char) exponent_x;
125         exponent_x = D;
126       }
127       ps[j] = '0' + (char) exponent_x;
128     } else {
129       ps[istart++] = '0';
130     }
131
132     ps[istart] = 0;
133
134     return;
135   }
136   // convert expon, coeff to ASCII
137   exponent_x -= DECIMAL_EXPONENT_BIAS;
138
139   ER10 = 0x1999999a;
140
141   istart = 0;
142   if (sign_x) {
143     ps[0] = '-';
144     istart = 1;
145   }
146   // if zero or non-canonical, set coefficient to '0'
147   if ((coefficient_x > 9999999999999999ull) ||  // non-canonical
148       ((coefficient_x == 0))    // significand is zero
149     ) {
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. */
176
177     Tmp = coefficient_x >> 59;
178     LO_18Dig = (coefficient_x << 5) >> 5;
179     HI_18Dig = 0;
180     k_lcv = 0;
181
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);
189     }
190
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;
196
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);
201     }
202     istart = istart + (c_ptr - c_ptr_start);
203   }
204
205   ps[istart++] = 'E';
206
207   if (exponent_x < 0) {
208     ps[istart++] = '-';
209     exponent_x = -exponent_x;
210   } else
211     ps[istart++] = '+';
212
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++;
220
221     j = istart + digits_x - 1;
222     istart = j + 1;
223
224     // 2^32/10
225     ER10 = 0x1999999a;
226
227     while (exponent_x > 9) {
228       D = (UINT64) exponent_x *ER10;
229       D >>= 32;
230       exponent_x = exponent_x - (D << 1) - (D << 3);
231
232       ps[j--] = '0' + (char) exponent_x;
233       exponent_x = D;
234     }
235     ps[j] = '0' + (char) exponent_x;
236   } else {
237     ps[istart++] = '0';
238   }
239
240   ps[istart] = 0;
241
242   return;
243
244 }
245
246
247
248 #if DECIMAL_CALL_BY_REFERENCE
249
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
255
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 =
265     0;
266   unsigned fpsc;
267   char c;
268
269 #if DECIMAL_CALL_BY_REFERENCE
270 #if !DECIMAL_GLOBAL_ROUNDING
271   _IDEC_round rnd_mode = *prnd_mode;
272 #endif
273 #endif
274
275   // eliminate leading whitespace
276   while (((*ps == ' ') || (*ps == '\t')) && (*ps))
277     ps++;
278
279   // get first non-whitespace character
280   c = *ps;
281
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);
293     }
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);
304     }
305   }
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);
319   }
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);
328   }
329   // determine sign
330   if (c == '-')
331     sign_x = 0x8000000000000000ull;
332   else
333     sign_x = 0;
334
335   // get next character if leading +/- sign
336   if (c == '-' || c == '+') {
337     ps++;
338     c = *ps;
339   }
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);
345   }
346
347   rdx_pt_enc = 0;
348
349   // detect zero (and eliminate/ignore leading zeros)
350   if (*(ps) == '0' || *(ps) == '.') {
351
352     if (*(ps) == '.') {
353       rdx_pt_enc = 1;
354       ps++;
355     }
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++;
364       }
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);
377           }
378           ps = ps + 1;
379         } else {
380           // if 2 radix points, return NaN
381           res = 0x7c00000000000000ull | sign_x;
382           BID_RETURN (res);
383         }
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);
389       }
390     }
391   }
392
393   c = *ps;
394
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);
402       }
403       rdx_pt_enc = 1;
404       ps++;
405       c = *ps;
406       continue;
407     }
408     dec_expon_scale += rdx_pt_enc;
409
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;
427         }
428       }
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;
438       }
439       if (c > '0')
440         rounded = 1;
441     }
442     ps++;
443     c = *ps;
444   }
445
446   add_expon -= (dec_expon_scale + right_radix_leading_zeros);
447
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);
454   }
455
456   if (c != 'E' && c != 'e') {
457     // return NaN
458     res = 0x7c00000000000000ull | sign_x;
459     BID_RETURN (res);
460   }
461   ps++;
462   c = *ps;
463   sgn_expon = (c == '-') ? 1 : 0;
464   if (c == '-' || c == '+') {
465     ps++;
466     c = *ps;
467   }
468   if (!c || c < '0' || c > '9') {
469     // return NaN
470     res = 0x7c00000000000000ull | sign_x;
471     BID_RETURN (res);
472   }
473
474   while (c >= '0' && c <= '9') {
475     expon_x = (expon_x << 1) + (expon_x << 3);
476     expon_x += (int) (c - '0');
477
478     ps++;
479     c = *ps;
480   }
481
482   if (c) {
483     // return NaN
484     res = 0x7c00000000000000ull | sign_x;
485     BID_RETURN (res);
486   }
487
488   if (sgn_expon)
489     expon_x = -expon_x;
490
491   expon_x += add_expon + DECIMAL_EXPONENT_BIAS;
492
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);
501   }
502   res = get_BID64 (sign_x, expon_x, coefficient_x, rnd_mode, &fpsc);
503   BID_RETURN (res);
504 }