1 /* Copyright (C) 2007-2018 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
bid64_to_string(char * ps,UINT64 * px _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM)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 }
512