OSDN Git Service

Licensing changes to GPLv3 resp. GPLv3 with GCC Runtime Exception.
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid64_string.c
1 /* Copyright (C) 2007, 2009  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 3, or (at your option) any later
8 version.
9
10 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 for more details.
14
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
18
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22 <http://www.gnu.org/licenses/>.  */
23
24 #include <ctype.h>
25 #include "bid_internal.h"
26 #include "bid128_2_str.h"
27 #include "bid128_2_str_macros.h"
28
29 #define MAX_FORMAT_DIGITS     16
30 #define DECIMAL_EXPONENT_BIAS 398
31 #define MAX_DECIMAL_EXPONENT  767
32
33 #if DECIMAL_CALL_BY_REFERENCE
34
35 void
36 bid64_to_string (char *ps, UINT64 * px
37                  _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
38   UINT64 x;
39 #else
40
41 void
42 bid64_to_string (char *ps, UINT64 x
43                  _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
44 #endif
45 // the destination string (pointed to by ps) must be pre-allocated
46   UINT64 sign_x, coefficient_x, D, ER10;
47   int istart, exponent_x, j, digits_x, bin_expon_cx;
48   int_float tempx;
49   UINT32 MiDi[12], *ptr;
50   UINT64 HI_18Dig, LO_18Dig, Tmp;
51   char *c_ptr_start, *c_ptr;
52   int midi_ind, k_lcv, len;
53   unsigned int save_fpsf;
54
55 #if DECIMAL_CALL_BY_REFERENCE
56   x = *px;
57 #endif
58
59   save_fpsf = *pfpsf; // place holder only
60   // unpack arguments, check for NaN or Infinity
61   if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) {
62     // x is Inf. or NaN or 0
63
64     // Inf or NaN?
65     if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) {
66       if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
67     ps[0] = (sign_x) ? '-' : '+';
68     ps[1] = ((x & MASK_SNAN) == MASK_SNAN)? 'S':'Q';
69         ps[2] = 'N';
70         ps[3] = 'a';
71         ps[4] = 'N';
72         ps[5] = 0;
73         return;
74       }
75       // x is Inf
76       ps[0] = (sign_x) ? '-' : '+';
77       ps[1] = 'I';
78       ps[2] = 'n';
79       ps[3] = 'f';
80       ps[4] = 0;
81       return;
82     }
83     // 0
84     istart = 0;
85     if (sign_x) {
86       ps[istart++] = '-';
87     }
88
89     ps[istart++] = '0';
90     ps[istart++] = 'E';
91
92     exponent_x -= 398;
93     if (exponent_x < 0) {
94       ps[istart++] = '-';
95       exponent_x = -exponent_x;
96     } else
97       ps[istart++] = '+';
98
99     if (exponent_x) {
100       // get decimal digits in coefficient_x
101       tempx.d = (float) exponent_x;
102       bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
103       digits_x = estimate_decimal_digits[bin_expon_cx];
104       if ((UINT64)exponent_x >= power10_table_128[digits_x].w[0])
105         digits_x++;
106
107       j = istart + digits_x - 1;
108       istart = j + 1;
109
110       // 2^32/10
111       ER10 = 0x1999999a;
112
113       while (exponent_x > 9) {
114         D = (UINT64) exponent_x *ER10;
115         D >>= 32;
116         exponent_x = exponent_x - (D << 1) - (D << 3);
117
118         ps[j--] = '0' + (char) exponent_x;
119         exponent_x = D;
120       }
121       ps[j] = '0' + (char) exponent_x;
122     } else {
123       ps[istart++] = '0';
124     }
125
126     ps[istart] = 0;
127
128     return;
129   }
130   // convert expon, coeff to ASCII
131   exponent_x -= DECIMAL_EXPONENT_BIAS;
132
133   ER10 = 0x1999999a;
134
135   istart = 0;
136   if (sign_x) {
137     ps[0] = '-';
138     istart = 1;
139   }
140   // if zero or non-canonical, set coefficient to '0'
141   if ((coefficient_x > 9999999999999999ull) ||  // non-canonical
142       ((coefficient_x == 0))    // significand is zero
143     ) {
144     ps[istart++] = '0';
145   } else {
146     /* ****************************************************
147        This takes a bid coefficient in C1.w[1],C1.w[0] 
148        and put the converted character sequence at location 
149        starting at &(str[k]). The function returns the number
150        of MiDi returned. Note that the character sequence 
151        does not have leading zeros EXCEPT when the input is of
152        zero value. It will then output 1 character '0'
153        The algorithm essentailly tries first to get a sequence of
154        Millenial Digits "MiDi" and then uses table lookup to get the
155        character strings of these MiDis.
156        **************************************************** */
157     /* Algorithm first decompose possibly 34 digits in hi and lo
158        18 digits. (The high can have at most 16 digits). It then
159        uses macro that handle 18 digit portions.
160        The first step is to get hi and lo such that
161        2^(64) C1.w[1] + C1.w[0] = hi * 10^18  + lo,   0 <= lo < 10^18.
162        We use a table lookup method to obtain the hi and lo 18 digits.
163        [C1.w[1],C1.w[0]] = c_8 2^(107) + c_7 2^(101) + ... + c_0 2^(59) + d
164        where 0 <= d < 2^59 and each c_j has 6 bits. Because d fits in
165        18 digits,  we set hi = 0, and lo = d to begin with.
166        We then retrieve from a table, for j = 0, 1, ..., 8
167        that gives us A and B where c_j 2^(59+6j) = A * 10^18 + B.
168        hi += A ; lo += B; After each accumulation into lo, we normalize 
169        immediately. So at the end, we have the decomposition as we need. */
170
171     Tmp = coefficient_x >> 59;
172     LO_18Dig = (coefficient_x << 5) >> 5;
173     HI_18Dig = 0;
174     k_lcv = 0;
175
176     while (Tmp) {
177       midi_ind = (int) (Tmp & 0x000000000000003FLL);
178       midi_ind <<= 1;
179       Tmp >>= 6;
180       HI_18Dig += mod10_18_tbl[k_lcv][midi_ind++];
181       LO_18Dig += mod10_18_tbl[k_lcv++][midi_ind];
182       __L0_Normalize_10to18 (HI_18Dig, LO_18Dig);
183     }
184
185     ptr = MiDi;
186     __L1_Split_MiDi_6_Lead (LO_18Dig, ptr);
187     len = ptr - MiDi;
188     c_ptr_start = &(ps[istart]);
189     c_ptr = c_ptr_start;
190
191     /* now convert the MiDi into character strings */
192     __L0_MiDi2Str_Lead (MiDi[0], c_ptr);
193     for (k_lcv = 1; k_lcv < len; k_lcv++) {
194       __L0_MiDi2Str (MiDi[k_lcv], c_ptr);
195     }
196     istart = istart + (c_ptr - c_ptr_start);
197   }
198
199   ps[istart++] = 'E';
200
201   if (exponent_x < 0) {
202     ps[istart++] = '-';
203     exponent_x = -exponent_x;
204   } else
205     ps[istart++] = '+';
206
207   if (exponent_x) {
208     // get decimal digits in coefficient_x
209     tempx.d = (float) exponent_x;
210     bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
211     digits_x = estimate_decimal_digits[bin_expon_cx];
212     if ((UINT64)exponent_x >= power10_table_128[digits_x].w[0])
213       digits_x++;
214
215     j = istart + digits_x - 1;
216     istart = j + 1;
217
218     // 2^32/10
219     ER10 = 0x1999999a;
220
221     while (exponent_x > 9) {
222       D = (UINT64) exponent_x *ER10;
223       D >>= 32;
224       exponent_x = exponent_x - (D << 1) - (D << 3);
225
226       ps[j--] = '0' + (char) exponent_x;
227       exponent_x = D;
228     }
229     ps[j] = '0' + (char) exponent_x;
230   } else {
231     ps[istart++] = '0';
232   }
233
234   ps[istart] = 0;
235
236   return;
237
238 }
239
240
241 #if DECIMAL_CALL_BY_REFERENCE
242 void
243 bid64_from_string (UINT64 * pres, char *ps
244                    _RND_MODE_PARAM _EXC_FLAGS_PARAM 
245                    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
246 #else
247 UINT64
248 bid64_from_string (char *ps
249                    _RND_MODE_PARAM _EXC_FLAGS_PARAM 
250                    _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
251 #endif
252   UINT64 sign_x, coefficient_x = 0, rounded = 0, res;
253   int expon_x = 0, sgn_expon, ndigits, add_expon = 0, midpoint =
254     0, rounded_up = 0;
255   int dec_expon_scale = 0, right_radix_leading_zeros = 0, rdx_pt_enc =
256     0;
257   unsigned fpsc;
258   char c;
259   unsigned int save_fpsf;
260
261 #if DECIMAL_CALL_BY_REFERENCE
262 #if !DECIMAL_GLOBAL_ROUNDING
263   _IDEC_round rnd_mode = *prnd_mode;
264 #endif
265 #endif
266
267   save_fpsf = *pfpsf; // place holder only
268   // eliminate leading whitespace
269   while (((*ps == ' ') || (*ps == '\t')) && (*ps))
270     ps++;
271
272   // get first non-whitespace character
273   c = *ps;
274
275   // detect special cases (INF or NaN)
276   if (!c || (c != '.' && c != '-' && c != '+' && (c < '0' || c > '9'))) {
277     // Infinity?
278     if ((tolower_macro (ps[0]) == 'i' && tolower_macro (ps[1]) == 'n' && 
279         tolower_macro (ps[2]) == 'f') && (!ps[3] || 
280         (tolower_macro (ps[3]) == 'i' && 
281         tolower_macro (ps[4]) == 'n' && tolower_macro (ps[5]) == 'i' && 
282         tolower_macro (ps[6]) == 't' && tolower_macro (ps[7]) == 'y' && 
283         !ps[8]))) {
284       res = 0x7800000000000000ull;
285       BID_RETURN (res);
286     }
287     // return sNaN
288     if (tolower_macro (ps[0]) == 's' && tolower_macro (ps[1]) == 'n' && 
289         tolower_macro (ps[2]) == 'a' && tolower_macro (ps[3]) == 'n') { 
290         // case insensitive check for snan
291       res = 0x7e00000000000000ull;
292       BID_RETURN (res);
293     } else {
294       // return qNaN
295       res = 0x7c00000000000000ull;
296       BID_RETURN (res);
297     }
298   }
299   // detect +INF or -INF
300   if ((tolower_macro (ps[1]) == 'i' && tolower_macro (ps[2]) == 'n' && 
301       tolower_macro (ps[3]) == 'f') && (!ps[4] || 
302       (tolower_macro (ps[4]) == 'i' && tolower_macro (ps[5]) == 'n' && 
303       tolower_macro (ps[6]) == 'i' && tolower_macro (ps[7]) == 't' && 
304       tolower_macro (ps[8]) == 'y' && !ps[9]))) {
305     if (c == '+')
306       res = 0x7800000000000000ull;
307     else if (c == '-')
308       res = 0xf800000000000000ull;
309     else
310       res = 0x7c00000000000000ull;
311     BID_RETURN (res);
312   }
313   // if +sNaN, +SNaN, -sNaN, or -SNaN
314   if (tolower_macro (ps[1]) == 's' && tolower_macro (ps[2]) == 'n'
315       && tolower_macro (ps[3]) == 'a' && tolower_macro (ps[4]) == 'n') {
316     if (c == '-')
317       res = 0xfe00000000000000ull;
318     else
319       res = 0x7e00000000000000ull;
320     BID_RETURN (res);
321   }
322   // determine sign
323   if (c == '-')
324     sign_x = 0x8000000000000000ull;
325   else
326     sign_x = 0;
327
328   // get next character if leading +/- sign
329   if (c == '-' || c == '+') {
330     ps++;
331     c = *ps;
332   }
333   // if c isn't a decimal point or a decimal digit, return NaN
334   if (c != '.' && (c < '0' || c > '9')) {
335     // return NaN
336     res = 0x7c00000000000000ull | sign_x;
337     BID_RETURN (res);
338   }
339
340   rdx_pt_enc = 0;
341
342   // detect zero (and eliminate/ignore leading zeros)
343   if (*(ps) == '0' || *(ps) == '.') {
344
345     if (*(ps) == '.') {
346       rdx_pt_enc = 1;
347       ps++;
348     }
349     // if all numbers are zeros (with possibly 1 radix point, the number is zero
350     // should catch cases such as: 000.0
351     while (*ps == '0') {
352       ps++;
353       // for numbers such as 0.0000000000000000000000000000000000001001, 
354       // we want to count the leading zeros
355       if (rdx_pt_enc) {
356         right_radix_leading_zeros++;
357       }
358       // if this character is a radix point, make sure we haven't already 
359       // encountered one
360       if (*(ps) == '.') {
361         if (rdx_pt_enc == 0) {
362           rdx_pt_enc = 1;
363           // if this is the first radix point, and the next character is NULL, 
364           // we have a zero
365           if (!*(ps + 1)) {
366             res =
367               ((UINT64) (398 - right_radix_leading_zeros) << 53) |
368               sign_x;
369             BID_RETURN (res);
370           }
371           ps = ps + 1;
372         } else {
373           // if 2 radix points, return NaN
374           res = 0x7c00000000000000ull | sign_x;
375           BID_RETURN (res);
376         }
377       } else if (!*(ps)) {
378         //pres->w[1] = 0x3040000000000000ull | sign_x;
379         res =
380           ((UINT64) (398 - right_radix_leading_zeros) << 53) | sign_x;
381         BID_RETURN (res);
382       }
383     }
384   }
385
386   c = *ps;
387
388   ndigits = 0;
389   while ((c >= '0' && c <= '9') || c == '.') {
390     if (c == '.') {
391       if (rdx_pt_enc) {
392         // return NaN
393         res = 0x7c00000000000000ull | sign_x;
394         BID_RETURN (res);
395       }
396       rdx_pt_enc = 1;
397       ps++;
398       c = *ps;
399       continue;
400     }
401     dec_expon_scale += rdx_pt_enc;
402
403     ndigits++;
404     if (ndigits <= 16) {
405       coefficient_x = (coefficient_x << 1) + (coefficient_x << 3);
406       coefficient_x += (UINT64) (c - '0');
407     } else if (ndigits == 17) {
408       // coefficient rounding
409                 switch(rnd_mode){
410         case ROUNDING_TO_NEAREST:
411       midpoint = (c == '5' && !(coefficient_x & 1)) ? 1 : 0; 
412           // if coefficient is even and c is 5, prepare to round up if 
413           // subsequent digit is nonzero
414       // if str[MAXDIG+1] > 5, we MUST round up
415       // if str[MAXDIG+1] == 5 and coefficient is ODD, ROUND UP!
416       if (c > '5' || (c == '5' && (coefficient_x & 1))) {
417         coefficient_x++;
418         rounded_up = 1;
419         break;
420
421         case ROUNDING_DOWN:
422                 if(sign_x) { coefficient_x++; rounded_up=1; }
423                 break;
424         case ROUNDING_UP:
425                 if(!sign_x) { coefficient_x++; rounded_up=1; }
426                 break;
427         case ROUNDING_TIES_AWAY:
428                 if(c>='5') { coefficient_x++; rounded_up=1; }
429                 break;
430           }
431         if (coefficient_x == 10000000000000000ull) {
432           coefficient_x = 1000000000000000ull;
433           add_expon = 1;
434         }
435       }
436       if (c > '0')
437         rounded = 1;
438       add_expon += 1;
439     } else { // ndigits > 17
440       add_expon++;
441       if (midpoint && c > '0') {
442         coefficient_x++;
443         midpoint = 0;
444         rounded_up = 1;
445       }
446       if (c > '0')
447         rounded = 1;
448     }
449     ps++;
450     c = *ps;
451   }
452
453   add_expon -= (dec_expon_scale + right_radix_leading_zeros);
454
455   if (!c) {
456     res =
457       fast_get_BID64_check_OF (sign_x,
458                                add_expon + DECIMAL_EXPONENT_BIAS,
459                                coefficient_x, 0, &fpsc);
460     BID_RETURN (res);
461   }
462
463   if (c != 'E' && c != 'e') {
464     // return NaN
465     res = 0x7c00000000000000ull | sign_x;
466     BID_RETURN (res);
467   }
468   ps++;
469   c = *ps;
470   sgn_expon = (c == '-') ? 1 : 0;
471   if (c == '-' || c == '+') {
472     ps++;
473     c = *ps;
474   }
475   if (!c || c < '0' || c > '9') {
476     // return NaN
477     res = 0x7c00000000000000ull | sign_x;
478     BID_RETURN (res);
479   }
480
481   while (c >= '0' && c <= '9') {
482     expon_x = (expon_x << 1) + (expon_x << 3);
483     expon_x += (int) (c - '0');
484
485     ps++;
486     c = *ps;
487   }
488
489   if (c) {
490     // return NaN
491     res = 0x7c00000000000000ull | sign_x;
492     BID_RETURN (res);
493   }
494
495   if (sgn_expon)
496     expon_x = -expon_x;
497
498   expon_x += add_expon + DECIMAL_EXPONENT_BIAS;
499
500   if (expon_x < 0) {
501     if (rounded_up)
502       coefficient_x--;
503     rnd_mode = 0;
504     res =
505       get_BID64_UF (sign_x, expon_x, coefficient_x, rounded, rnd_mode,
506                     &fpsc);
507     BID_RETURN (res);
508   }
509   res = get_BID64 (sign_x, expon_x, coefficient_x, rnd_mode, &fpsc);
510   BID_RETURN (res);
511 }