1/* Copyright (C) 2007-2015 Free Software Foundation, Inc.
2
3This file is part of GCC.
4
5GCC is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free
7Software Foundation; either version 3, or (at your option) any later
8version.
9
10GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13for more details.
14
15Under Section 7 of GPL version 3, you are granted additional
16permissions described in the GCC Runtime Library Exception, version
173.1, as published by the Free Software Foundation.
18
19You should have received a copy of the GNU General Public License and
20a copy of the GCC Runtime Library Exception along with this program;
21see 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
35void
36bid64_to_string (char *ps, UINT64 * px
37		 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
38  UINT64 x;
39#else
40
41void
42bid64_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
242void
243bid64_from_string (UINT64 * pres, char *ps
244		   _RND_MODE_PARAM _EXC_FLAGS_PARAM
245                   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
246#else
247UINT64
248bid64_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