1 /* Copyright (C) 2007 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 2, or (at your option) any later
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
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
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
30 #include "bid_internal.h"
32 #define MAX_FORMAT_DIGITS_128 34
33 #define MAX_STRING_DIGITS_128 100
34 #define MAX_SEARCH MAX_STRING_DIGITS_128-MAX_FORMAT_DIGITS_128-1
37 #if DECIMAL_CALL_BY_REFERENCE
40 __bid128_from_string (UINT128 * pres,
41 char *ps _RND_MODE_PARAM _EXC_FLAGS_PARAM
42 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
46 __bid128_from_string (char *ps _RND_MODE_PARAM _EXC_FLAGS_PARAM
47 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
50 UINT64 sign_x, coeff_high, coeff_low, coeff2, coeff_l2, carry,
51 scale_high, right_radix_leading_zeros;
52 int ndigits_before, ndigits_after, ndigits_total, dec_expon, sgn_exp,
54 char c, buffer[MAX_STRING_DIGITS_128];
56 #if DECIMAL_CALL_BY_REFERENCE
57 #if !DECIMAL_GLOBAL_ROUNDING
58 _IDEC_round rnd_mode = *prnd_mode;
62 right_radix_leading_zeros = rdx_pt_enc = 0;
64 // if null string, return NaN
66 res.w[1] = 0x7c00000000000000ull;
70 // eliminate leading white space
71 while ((*ps == ' ') || (*ps == '\t'))
74 // c gets first character
78 // if c is null or not equal to a (radix point, negative sign,
79 // positive sign, or number) it might be SNaN, sNaN, Infinity
81 || (c != '.' && c != '-' && c != '+'
82 && ((unsigned) (c - '0') > 9))) {
85 if ((tolower_macro (ps[0]) == 'i' && tolower_macro (ps[1]) == 'n'
86 && tolower_macro (ps[2]) == 'f')
88 || (tolower_macro (ps[3]) == 'i'
89 && tolower_macro (ps[4]) == 'n'
90 && tolower_macro (ps[5]) == 'i'
91 && tolower_macro (ps[6]) == 't'
92 && tolower_macro (ps[7]) == 'y' && !ps[8])
94 res.w[1] = 0x7800000000000000ull;
98 if (tolower_macro (ps[0]) == 's' && tolower_macro (ps[1]) == 'n' &&
99 tolower_macro (ps[2]) == 'a' && tolower_macro (ps[3]) == 'n') {
100 // case insensitive check for snan
101 res.w[1] = 0x7e00000000000000ull;
105 res.w[1] = 0x7c00000000000000ull;
109 // if +Inf, -Inf, +Infinity, or -Infinity (case insensitive check for inf)
110 if ((tolower_macro (ps[1]) == 'i' && tolower_macro (ps[2]) == 'n' &&
111 tolower_macro (ps[3]) == 'f') && (!ps[4] ||
112 (tolower_macro (ps[4]) == 'i' && tolower_macro (ps[5]) == 'n' &&
113 tolower_macro (ps[6]) == 'i' && tolower_macro (ps[7]) == 't' &&
114 tolower_macro (ps[8]) == 'y' && !ps[9]))) { // ci check for infinity
118 res.w[1] = 0x7800000000000000ull;
120 res.w[1] = 0xf800000000000000ull;
122 res.w[1] = 0x7c00000000000000ull;
126 // if +sNaN, +SNaN, -sNaN, or -SNaN
127 if (tolower_macro (ps[1]) == 's' && tolower_macro (ps[2]) == 'n'
128 && tolower_macro (ps[3]) == 'a' && tolower_macro (ps[4]) == 'n') {
131 res.w[1] = 0xfe00000000000000ull;
133 res.w[1] = 0x7e00000000000000ull;
136 // set up sign_x to be OR'ed with the upper word later
138 sign_x = 0x8000000000000000ull;
142 // go to next character if leading sign
143 if (c == '-' || c == '+')
148 // if c isn't a decimal point or a decimal digit, return NaN
149 if (c != '.' && ((unsigned) (c - '0') > 9)) {
150 res.w[1] = 0x7c00000000000000ull | sign_x;
154 // detect zero (and eliminate/ignore leading zeros)
157 // if all numbers are zeros (with possibly 1 radix point, the number is zero
158 // should catch cases such as: 000.0
163 // for numbers such as 0.0000000000000000000000000000000000001001,
164 // we want to count the leading zeros
166 right_radix_leading_zeros++;
168 // if this character is a radix point, make sure we haven't already
171 if (rdx_pt_enc == 0) {
173 // if this is the first radix point, and the next character is NULL,
177 (0x3040000000000000ull -
178 (right_radix_leading_zeros << 49)) | sign_x;
184 // if 2 radix points, return NaN
185 res.w[1] = 0x7c00000000000000ull | sign_x;
190 //res.w[1] = 0x3040000000000000ull | sign_x;
192 (0x3040000000000000ull -
193 (right_radix_leading_zeros << 49)) | sign_x;
202 // initialize local variables
203 ndigits_before = ndigits_after = ndigits_total = 0;
205 // pstart_coefficient = ps;
208 // investigate string (before radix point)
209 while ((unsigned) (c - '0') <= 9
210 && ndigits_before < MAX_STRING_DIGITS_128) {
211 buffer[ndigits_before] = c;
217 ndigits_total = ndigits_before;
222 // investigate string (after radix point)
223 while ((unsigned) (c - '0') <= 9
224 && ndigits_total < MAX_STRING_DIGITS_128) {
225 buffer[ndigits_total] = c;
230 ndigits_after = ndigits_total - ndigits_before;
234 // we encountered a radix point while detecting zeros
239 // investigate string (after radix point)
240 while ((unsigned) (c - '0') <= 9
241 && ndigits_total < MAX_STRING_DIGITS_128) {
242 buffer[ndigits_total] = c;
247 ndigits_after = ndigits_total - ndigits_before;
252 if (ndigits_total < MAX_STRING_DIGITS_128) {
254 if (c != 'e' && c != 'E') {
256 res.w[1] = 0x7c00000000000000ull;
263 if (((unsigned) (c - '0') > 9)
264 && ((c != '+' && c != '-') || (unsigned) (ps[1] - '0') > 9)) {
266 res.w[1] = 0x7c00000000000000ull;
275 } else if (c == '+') {
284 while (((unsigned) c) <= 9 && i < 7) {
285 d2 = dec_expon + dec_expon;
286 dec_expon = (d2 << 2) + d2 + c;
293 dec_expon = (dec_expon + sgn_exp) ^ sgn_exp;
297 if (ndigits_total <= MAX_FORMAT_DIGITS_128) {
299 DECIMAL_EXPONENT_BIAS_128 - ndigits_after -
300 right_radix_leading_zeros;
302 res.w[1] = 0 | sign_x;
305 if (ndigits_total == 0) {
308 } else if (ndigits_total <= 19) {
309 coeff_high = buffer[0] - '0';
310 for (i = 1; i < ndigits_total; i++) {
311 coeff2 = coeff_high + coeff_high;
312 coeff_high = (coeff2 << 2) + coeff2 + buffer[i] - '0';
314 CX.w[0] = coeff_high;
317 coeff_high = buffer[0] - '0';
318 for (i = 1; i < ndigits_total - 17; i++) {
319 coeff2 = coeff_high + coeff_high;
320 coeff_high = (coeff2 << 2) + coeff2 + buffer[i] - '0';
322 coeff_low = buffer[i] - '0';
324 for (; i < ndigits_total; i++) {
325 coeff_l2 = coeff_low + coeff_low;
326 coeff_low = (coeff_l2 << 2) + coeff_l2 + buffer[i] - '0';
328 // now form the coefficient as coeff_high*10^19+coeff_low+carry
329 scale_high = 100000000000000000ull;
330 __mul_64x64_to_128_fast (CX, coeff_high, scale_high);
332 CX.w[0] += coeff_low;
333 if (CX.w[0] < coeff_low)
336 get_BID128_string (&res, sign_x, dec_expon, CX);
339 // simply round using the digits that were read
342 ndigits_before + DECIMAL_EXPONENT_BIAS_128 -
343 MAX_FORMAT_DIGITS_128 - right_radix_leading_zeros;
346 res.w[1] = 0 | sign_x;
350 coeff_high = buffer[0] - '0';
351 for (i = 1; i < MAX_FORMAT_DIGITS_128 - 17; i++) {
352 coeff2 = coeff_high + coeff_high;
353 coeff_high = (coeff2 << 2) + coeff2 + buffer[i] - '0';
355 coeff_low = buffer[i] - '0';
357 for (; i < MAX_FORMAT_DIGITS_128; i++) {
358 coeff_l2 = coeff_low + coeff_low;
359 coeff_low = (coeff_l2 << 2) + coeff_l2 + buffer[i] - '0';
361 carry = ((unsigned) ('4' - buffer[i])) >> 31;
362 if ((buffer[i] == '5' && !(coeff_low & 1)) || dec_expon < 0) {
363 if (dec_expon >= 0) {
367 for (; i < ndigits_total; i++) {
368 if (buffer[i] > '0') {
374 // now form the coefficient as coeff_high*10^17+coeff_low+carry
375 scale_high = 100000000000000000ull;
377 if (dec_expon > -MAX_FORMAT_DIGITS_128) {
378 scale_high = 1000000000000000000ull;
379 coeff_low = (coeff_low << 3) + (coeff_low << 1);
382 if (dec_expon == -MAX_FORMAT_DIGITS_128
383 && coeff_high > 50000000000000000ull)
387 __mul_64x64_to_128_fast (CX, coeff_high, scale_high);
390 CX.w[0] += coeff_low;
391 if (CX.w[0] < coeff_low)
394 get_BID128_string (&res, sign_x, dec_expon, CX);