1 /* Copyright (C) 2007-2023 Free Software Foundation, Inc.
3 This file is part of GCC.
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
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
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.
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/>. */
25 #include "bid_internal.h"
26 #include "bid128_2_str.h"
27 #include "bid128_2_str_macros.h"
29 #define MAX_FORMAT_DIGITS 16
30 #define DECIMAL_EXPONENT_BIAS 398
31 #define MAX_DECIMAL_EXPONENT 767
33 #if DECIMAL_CALL_BY_REFERENCE
36 bid64_to_string (char *ps
, UINT64
* px
37 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
42 bid64_to_string (char *ps
, UINT64 x
43 _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
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
;
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
;
55 #if DECIMAL_CALL_BY_REFERENCE
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
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';
76 ps
[0] = (sign_x
) ? '-' : '+';
95 exponent_x
= -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])
107 j
= istart
+ digits_x
- 1;
113 while (exponent_x
> 9) {
114 D
= (UINT64
) exponent_x
*ER10
;
116 exponent_x
= exponent_x
- (D
<< 1) - (D
<< 3);
118 ps
[j
--] = '0' + (char) exponent_x
;
121 ps
[j
] = '0' + (char) exponent_x
;
130 // convert expon, coeff to ASCII
131 exponent_x
-= DECIMAL_EXPONENT_BIAS
;
140 // if zero or non-canonical, set coefficient to '0'
141 if ((coefficient_x
> 9999999999999999ull) || // non-canonical
142 ((coefficient_x
== 0)) // significand is zero
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. */
171 Tmp
= coefficient_x
>> 59;
172 LO_18Dig
= (coefficient_x
<< 5) >> 5;
177 midi_ind
= (int) (Tmp
& 0x000000000000003FLL
);
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
);
186 __L1_Split_MiDi_6_Lead (LO_18Dig
, ptr
);
188 c_ptr_start
= &(ps
[istart
]);
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
);
196 istart
= istart
+ (c_ptr
- c_ptr_start
);
201 if (exponent_x
< 0) {
203 exponent_x
= -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])
215 j
= istart
+ digits_x
- 1;
221 while (exponent_x
> 9) {
222 D
= (UINT64
) exponent_x
*ER10
;
224 exponent_x
= exponent_x
- (D
<< 1) - (D
<< 3);
226 ps
[j
--] = '0' + (char) exponent_x
;
229 ps
[j
] = '0' + (char) exponent_x
;
241 #if DECIMAL_CALL_BY_REFERENCE
243 bid64_from_string (UINT64
* pres
, char *ps
244 _RND_MODE_PARAM _EXC_FLAGS_PARAM
245 _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
248 bid64_from_string (char *ps
249 _RND_MODE_PARAM _EXC_FLAGS_PARAM
250 _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
252 UINT64 sign_x
, coefficient_x
= 0, rounded
= 0, res
;
253 int expon_x
= 0, sgn_expon
, ndigits
, add_expon
= 0, midpoint
=
255 int dec_expon_scale
= 0, right_radix_leading_zeros
= 0, rdx_pt_enc
=
259 unsigned int save_fpsf
;
261 #if DECIMAL_CALL_BY_REFERENCE
262 #if !DECIMAL_GLOBAL_ROUNDING
263 _IDEC_round rnd_mode
= *prnd_mode
;
267 save_fpsf
= *pfpsf
; // place holder only
268 // eliminate leading whitespace
269 while (((*ps
== ' ') || (*ps
== '\t')) && (*ps
))
272 // get first non-whitespace character
275 // detect special cases (INF or NaN)
276 if (!c
|| (c
!= '.' && c
!= '-' && c
!= '+' && (c
< '0' || c
> '9'))) {
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' &&
284 res
= 0x7800000000000000ull
;
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
;
295 res
= 0x7c00000000000000ull
;
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]))) {
306 res
= 0x7800000000000000ull
;
308 res
= 0xf800000000000000ull
;
310 res
= 0x7c00000000000000ull
;
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') {
317 res
= 0xfe00000000000000ull
;
319 res
= 0x7e00000000000000ull
;
324 sign_x
= 0x8000000000000000ull
;
328 // get next character if leading +/- sign
329 if (c
== '-' || c
== '+') {
333 // if c isn't a decimal point or a decimal digit, return NaN
334 if (c
!= '.' && (c
< '0' || c
> '9')) {
336 res
= 0x7c00000000000000ull
| sign_x
;
342 // detect zero (and eliminate/ignore leading zeros)
343 if (*(ps
) == '0' || *(ps
) == '.') {
349 // if all numbers are zeros (with possibly 1 radix point, the number is zero
350 // should catch cases such as: 000.0
353 // for numbers such as 0.0000000000000000000000000000000000001001,
354 // we want to count the leading zeros
356 right_radix_leading_zeros
++;
358 // if this character is a radix point, make sure we haven't already
361 if (rdx_pt_enc
== 0) {
363 // if this is the first radix point, and the next character is NULL,
367 ((UINT64
) (398 - right_radix_leading_zeros
) << 53) |
373 // if 2 radix points, return NaN
374 res
= 0x7c00000000000000ull
| sign_x
;
378 //pres->w[1] = 0x3040000000000000ull | sign_x;
380 ((UINT64
) (398 - right_radix_leading_zeros
) << 53) | sign_x
;
389 while ((c
>= '0' && c
<= '9') || c
== '.') {
393 res
= 0x7c00000000000000ull
| sign_x
;
401 dec_expon_scale
+= rdx_pt_enc
;
405 coefficient_x
= (coefficient_x
<< 1) + (coefficient_x
<< 3);
406 coefficient_x
+= (UINT64
) (c
- '0');
407 } else if (ndigits
== 17) {
408 // coefficient rounding
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))) {
422 if(sign_x
) { coefficient_x
++; rounded_up
=1; }
425 if(!sign_x
) { coefficient_x
++; rounded_up
=1; }
427 case ROUNDING_TIES_AWAY
:
428 if(c
>='5') { coefficient_x
++; rounded_up
=1; }
431 if (coefficient_x
== 10000000000000000ull) {
432 coefficient_x
= 1000000000000000ull;
439 } else { // ndigits > 17
441 if (midpoint
&& c
> '0') {
453 add_expon
-= (dec_expon_scale
+ right_radix_leading_zeros
);
457 fast_get_BID64_check_OF (sign_x
,
458 add_expon
+ DECIMAL_EXPONENT_BIAS
,
459 coefficient_x
, 0, &fpsc
);
463 if (c
!= 'E' && c
!= 'e') {
465 res
= 0x7c00000000000000ull
| sign_x
;
470 sgn_expon
= (c
== '-') ? 1 : 0;
471 if (c
== '-' || c
== '+') {
475 if (!c
|| c
< '0' || c
> '9') {
477 res
= 0x7c00000000000000ull
| sign_x
;
481 while (c
>= '0' && c
<= '9') {
482 expon_x
= (expon_x
<< 1) + (expon_x
<< 3);
483 expon_x
+= (int) (c
- '0');
491 res
= 0x7c00000000000000ull
| sign_x
;
498 expon_x
+= add_expon
+ DECIMAL_EXPONENT_BIAS
;
505 get_BID64_UF (sign_x
, expon_x
, coefficient_x
, rounded
, rnd_mode
,
509 res
= get_BID64 (sign_x
, expon_x
, coefficient_x
, rnd_mode
, &fpsc
);