OSDN Git Service

2007-12-19 Etsushi Kato <ek.kato@gmail.com>
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid64_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                  _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
43   UINT64 x;
44 #else
45
46 void
47 bid64_to_string (char *ps, UINT64 x
48                  _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
49 #endif
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;
53   int_float tempx;
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;
59
60 #if DECIMAL_CALL_BY_REFERENCE
61   x = *px;
62 #endif
63
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
68
69     // Inf or NaN?
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';
74         ps[2] = 'N';
75         ps[3] = 'a';
76         ps[4] = 'N';
77         ps[5] = 0;
78         return;
79       }
80       // x is Inf
81       ps[0] = (sign_x) ? '-' : '+';
82       ps[1] = 'I';
83       ps[2] = 'n';
84       ps[3] = 'f';
85       ps[4] = 0;
86       return;
87     }
88     // 0
89     istart = 0;
90     if (sign_x) {
91       ps[istart++] = '-';
92     }
93
94     ps[istart++] = '0';
95     ps[istart++] = 'E';
96
97     exponent_x -= 398;
98     if (exponent_x < 0) {
99       ps[istart++] = '-';
100       exponent_x = -exponent_x;
101     } else
102       ps[istart++] = '+';
103
104     if (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])
110         digits_x++;
111
112       j = istart + digits_x - 1;
113       istart = j + 1;
114
115       // 2^32/10
116       ER10 = 0x1999999a;
117
118       while (exponent_x > 9) {
119         D = (UINT64) exponent_x *ER10;
120         D >>= 32;
121         exponent_x = exponent_x - (D << 1) - (D << 3);
122
123         ps[j--] = '0' + (char) exponent_x;
124         exponent_x = D;
125       }
126       ps[j] = '0' + (char) exponent_x;
127     } else {
128       ps[istart++] = '0';
129     }
130
131     ps[istart] = 0;
132
133     return;
134   }
135   // convert expon, coeff to ASCII
136   exponent_x -= DECIMAL_EXPONENT_BIAS;
137
138   ER10 = 0x1999999a;
139
140   istart = 0;
141   if (sign_x) {
142     ps[0] = '-';
143     istart = 1;
144   }
145   // if zero or non-canonical, set coefficient to '0'
146   if ((coefficient_x > 9999999999999999ull) ||  // non-canonical
147       ((coefficient_x == 0))    // significand is zero
148     ) {
149     ps[istart++] = '0';
150   } else {
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. */
175
176     Tmp = coefficient_x >> 59;
177     LO_18Dig = (coefficient_x << 5) >> 5;
178     HI_18Dig = 0;
179     k_lcv = 0;
180
181     while (Tmp) {
182       midi_ind = (int) (Tmp & 0x000000000000003FLL);
183       midi_ind <<= 1;
184       Tmp >>= 6;
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);
188     }
189
190     ptr = MiDi;
191     __L1_Split_MiDi_6_Lead (LO_18Dig, ptr);
192     len = ptr - MiDi;
193     c_ptr_start = &(ps[istart]);
194     c_ptr = c_ptr_start;
195
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);
200     }
201     istart = istart + (c_ptr - c_ptr_start);
202   }
203
204   ps[istart++] = 'E';
205
206   if (exponent_x < 0) {
207     ps[istart++] = '-';
208     exponent_x = -exponent_x;
209   } else
210     ps[istart++] = '+';
211
212   if (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])
218       digits_x++;
219
220     j = istart + digits_x - 1;
221     istart = j + 1;
222
223     // 2^32/10
224     ER10 = 0x1999999a;
225
226     while (exponent_x > 9) {
227       D = (UINT64) exponent_x *ER10;
228       D >>= 32;
229       exponent_x = exponent_x - (D << 1) - (D << 3);
230
231       ps[j--] = '0' + (char) exponent_x;
232       exponent_x = D;
233     }
234     ps[j] = '0' + (char) exponent_x;
235   } else {
236     ps[istart++] = '0';
237   }
238
239   ps[istart] = 0;
240
241   return;
242
243 }
244
245
246 #if DECIMAL_CALL_BY_REFERENCE
247 void
248 bid64_from_string (UINT64 * pres, char *ps
249                    _RND_MODE_PARAM _EXC_FLAGS_PARAM 
250                    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
251 #else
252 UINT64
253 bid64_from_string (char *ps
254                    _RND_MODE_PARAM _EXC_FLAGS_PARAM 
255                    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
256 #endif
257   UINT64 sign_x, coefficient_x = 0, rounded = 0, res;
258   int expon_x = 0, sgn_expon, ndigits, add_expon = 0, midpoint =
259     0, rounded_up = 0;
260   int dec_expon_scale = 0, right_radix_leading_zeros = 0, rdx_pt_enc =
261     0;
262   unsigned fpsc;
263   char c;
264   unsigned int save_fpsf;
265
266 #if DECIMAL_CALL_BY_REFERENCE
267 #if !DECIMAL_GLOBAL_ROUNDING
268   _IDEC_round rnd_mode = *prnd_mode;
269 #endif
270 #endif
271
272   save_fpsf = *pfpsf; // place holder only
273   // eliminate leading whitespace
274   while (((*ps == ' ') || (*ps == '\t')) && (*ps))
275     ps++;
276
277   // get first non-whitespace character
278   c = *ps;
279
280   // detect special cases (INF or NaN)
281   if (!c || (c != '.' && c != '-' && c != '+' && (c < '0' || c > '9'))) {
282     // Infinity?
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' && 
288         !ps[8]))) {
289       res = 0x7800000000000000ull;
290       BID_RETURN (res);
291     }
292     // return sNaN
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;
297       BID_RETURN (res);
298     } else {
299       // return qNaN
300       res = 0x7c00000000000000ull;
301       BID_RETURN (res);
302     }
303   }
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]))) {
310     if (c == '+')
311       res = 0x7800000000000000ull;
312     else if (c == '-')
313       res = 0xf800000000000000ull;
314     else
315       res = 0x7c00000000000000ull;
316     BID_RETURN (res);
317   }
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') {
321     if (c == '-')
322       res = 0xfe00000000000000ull;
323     else
324       res = 0x7e00000000000000ull;
325     BID_RETURN (res);
326   }
327   // determine sign
328   if (c == '-')
329     sign_x = 0x8000000000000000ull;
330   else
331     sign_x = 0;
332
333   // get next character if leading +/- sign
334   if (c == '-' || c == '+') {
335     ps++;
336     c = *ps;
337   }
338   // if c isn't a decimal point or a decimal digit, return NaN
339   if (c != '.' && (c < '0' || c > '9')) {
340     // return NaN
341     res = 0x7c00000000000000ull | sign_x;
342     BID_RETURN (res);
343   }
344
345   rdx_pt_enc = 0;
346
347   // detect zero (and eliminate/ignore leading zeros)
348   if (*(ps) == '0' || *(ps) == '.') {
349
350     if (*(ps) == '.') {
351       rdx_pt_enc = 1;
352       ps++;
353     }
354     // if all numbers are zeros (with possibly 1 radix point, the number is zero
355     // should catch cases such as: 000.0
356     while (*ps == '0') {
357       ps++;
358       // for numbers such as 0.0000000000000000000000000000000000001001, 
359       // we want to count the leading zeros
360       if (rdx_pt_enc) {
361         right_radix_leading_zeros++;
362       }
363       // if this character is a radix point, make sure we haven't already 
364       // encountered one
365       if (*(ps) == '.') {
366         if (rdx_pt_enc == 0) {
367           rdx_pt_enc = 1;
368           // if this is the first radix point, and the next character is NULL, 
369           // we have a zero
370           if (!*(ps + 1)) {
371             res =
372               ((UINT64) (398 - right_radix_leading_zeros) << 53) |
373               sign_x;
374             BID_RETURN (res);
375           }
376           ps = ps + 1;
377         } else {
378           // if 2 radix points, return NaN
379           res = 0x7c00000000000000ull | sign_x;
380           BID_RETURN (res);
381         }
382       } else if (!*(ps)) {
383         //pres->w[1] = 0x3040000000000000ull | sign_x;
384         res =
385           ((UINT64) (398 - right_radix_leading_zeros) << 53) | sign_x;
386         BID_RETURN (res);
387       }
388     }
389   }
390
391   c = *ps;
392
393   ndigits = 0;
394   while ((c >= '0' && c <= '9') || c == '.') {
395     if (c == '.') {
396       if (rdx_pt_enc) {
397         // return NaN
398         res = 0x7c00000000000000ull | sign_x;
399         BID_RETURN (res);
400       }
401       rdx_pt_enc = 1;
402       ps++;
403       c = *ps;
404       continue;
405     }
406     dec_expon_scale += rdx_pt_enc;
407
408     ndigits++;
409     if (ndigits <= 16) {
410       coefficient_x = (coefficient_x << 1) + (coefficient_x << 3);
411       coefficient_x += (UINT64) (c - '0');
412     } else if (ndigits == 17) {
413       // coefficient rounding
414                 switch(rnd_mode){
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))) {
422         coefficient_x++;
423         rounded_up = 1;
424         break;
425
426         case ROUNDING_DOWN:
427                 if(sign_x) { coefficient_x++; rounded_up=1; }
428                 break;
429         case ROUNDING_UP:
430                 if(!sign_x) { coefficient_x++; rounded_up=1; }
431                 break;
432         case ROUNDING_TIES_AWAY:
433                 if(c>='5') { coefficient_x++; rounded_up=1; }
434                 break;
435           }
436         if (coefficient_x == 10000000000000000ull) {
437           coefficient_x = 1000000000000000ull;
438           add_expon = 1;
439         }
440       }
441       if (c > '0')
442         rounded = 1;
443       add_expon += 1;
444     } else { // ndigits > 17
445       add_expon++;
446       if (midpoint && c > '0') {
447         coefficient_x++;
448         midpoint = 0;
449         rounded_up = 1;
450       }
451       if (c > '0')
452         rounded = 1;
453     }
454     ps++;
455     c = *ps;
456   }
457
458   add_expon -= (dec_expon_scale + right_radix_leading_zeros);
459
460   if (!c) {
461     res =
462       fast_get_BID64_check_OF (sign_x,
463                                add_expon + DECIMAL_EXPONENT_BIAS,
464                                coefficient_x, 0, &fpsc);
465     BID_RETURN (res);
466   }
467
468   if (c != 'E' && c != 'e') {
469     // return NaN
470     res = 0x7c00000000000000ull | sign_x;
471     BID_RETURN (res);
472   }
473   ps++;
474   c = *ps;
475   sgn_expon = (c == '-') ? 1 : 0;
476   if (c == '-' || c == '+') {
477     ps++;
478     c = *ps;
479   }
480   if (!c || c < '0' || c > '9') {
481     // return NaN
482     res = 0x7c00000000000000ull | sign_x;
483     BID_RETURN (res);
484   }
485
486   while (c >= '0' && c <= '9') {
487     expon_x = (expon_x << 1) + (expon_x << 3);
488     expon_x += (int) (c - '0');
489
490     ps++;
491     c = *ps;
492   }
493
494   if (c) {
495     // return NaN
496     res = 0x7c00000000000000ull | sign_x;
497     BID_RETURN (res);
498   }
499
500   if (sgn_expon)
501     expon_x = -expon_x;
502
503   expon_x += add_expon + DECIMAL_EXPONENT_BIAS;
504
505   if (expon_x < 0) {
506     if (rounded_up)
507       coefficient_x--;
508     rnd_mode = 0;
509     res =
510       get_BID64_UF (sign_x, expon_x, coefficient_x, rounded, rnd_mode,
511                     &fpsc);
512     BID_RETURN (res);
513   }
514   res = get_BID64 (sign_x, expon_x, coefficient_x, rnd_mode, &fpsc);
515   BID_RETURN (res);
516 }