2008-01-10 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / libgcc / config / libbid / bid128_fromstring.c
blobd92c135bca0618cefe0e25d85c880f719092052d
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
8 version.
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
17 executable.)
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
22 for more details.
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
27 02110-1301, USA. */
29 #define BID_128RES
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
39 void
40 __bid128_from_string (UINT128 * pres,
41 char *ps _RND_MODE_PARAM _EXC_FLAGS_PARAM
42 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
43 #else
45 UINT128
46 __bid128_from_string (char *ps _RND_MODE_PARAM _EXC_FLAGS_PARAM
47 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
48 #endif
49 UINT128 CX, res;
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,
53 i, d2, rdx_pt_enc;
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;
59 #endif
60 #endif
62 right_radix_leading_zeros = rdx_pt_enc = 0;
64 // if null string, return NaN
65 if (!ps) {
66 res.w[1] = 0x7c00000000000000ull;
67 res.w[0] = 0;
68 BID_RETURN (res);
70 // eliminate leading white space
71 while ((*ps == ' ') || (*ps == '\t'))
72 ps++;
74 // c gets first character
75 c = *ps;
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
80 if (!c
81 || (c != '.' && c != '-' && c != '+'
82 && ((unsigned) (c - '0') > 9))) {
83 res.w[0] = 0;
84 // Infinity?
85 if ((tolower_macro (ps[0]) == 'i' && tolower_macro (ps[1]) == 'n'
86 && tolower_macro (ps[2]) == 'f')
87 && (!ps[3]
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])
93 )) {
94 res.w[1] = 0x7800000000000000ull;
95 BID_RETURN (res);
97 // return sNaN
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;
102 BID_RETURN (res);
103 } else {
104 // return qNaN
105 res.w[1] = 0x7c00000000000000ull;
106 BID_RETURN (res);
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
115 res.w[0] = 0;
117 if (c == '+')
118 res.w[1] = 0x7800000000000000ull;
119 else if (c == '-')
120 res.w[1] = 0xf800000000000000ull;
121 else
122 res.w[1] = 0x7c00000000000000ull;
124 BID_RETURN (res);
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') {
129 res.w[0] = 0;
130 if (c == '-')
131 res.w[1] = 0xfe00000000000000ull;
132 else
133 res.w[1] = 0x7e00000000000000ull;
134 BID_RETURN (res);
136 // set up sign_x to be OR'ed with the upper word later
137 if (c == '-')
138 sign_x = 0x8000000000000000ull;
139 else
140 sign_x = 0;
142 // go to next character if leading sign
143 if (c == '-' || c == '+')
144 ps++;
146 c = *ps;
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;
151 res.w[0] = 0;
152 BID_RETURN (res);
154 // detect zero (and eliminate/ignore leading zeros)
155 if (*(ps) == '0') {
157 // if all numbers are zeros (with possibly 1 radix point, the number is zero
158 // should catch cases such as: 000.0
159 while (*ps == '0') {
161 ps++;
163 // for numbers such as 0.0000000000000000000000000000000000001001,
164 // we want to count the leading zeros
165 if (rdx_pt_enc) {
166 right_radix_leading_zeros++;
168 // if this character is a radix point, make sure we haven't already
169 // encountered one
170 if (*(ps) == '.') {
171 if (rdx_pt_enc == 0) {
172 rdx_pt_enc = 1;
173 // if this is the first radix point, and the next character is NULL,
174 // we have a zero
175 if (!*(ps + 1)) {
176 res.w[1] =
177 (0x3040000000000000ull -
178 (right_radix_leading_zeros << 49)) | sign_x;
179 res.w[0] = 0;
180 BID_RETURN (res);
182 ps = ps + 1;
183 } else {
184 // if 2 radix points, return NaN
185 res.w[1] = 0x7c00000000000000ull | sign_x;
186 res.w[0] = 0;
187 BID_RETURN (res);
189 } else if (!*(ps)) {
190 //res.w[1] = 0x3040000000000000ull | sign_x;
191 res.w[1] =
192 (0x3040000000000000ull -
193 (right_radix_leading_zeros << 49)) | sign_x;
194 res.w[0] = 0;
195 BID_RETURN (res);
200 c = *ps;
202 // initialize local variables
203 ndigits_before = ndigits_after = ndigits_total = 0;
204 sgn_exp = 0;
205 // pstart_coefficient = ps;
207 if (!rdx_pt_enc) {
208 // investigate string (before radix point)
209 while ((unsigned) (c - '0') <= 9
210 && ndigits_before < MAX_STRING_DIGITS_128) {
211 buffer[ndigits_before] = c;
212 ps++;
213 c = *ps;
214 ndigits_before++;
217 ndigits_total = ndigits_before;
218 if (c == '.') {
219 ps++;
220 if ((c = *ps)) {
222 // investigate string (after radix point)
223 while ((unsigned) (c - '0') <= 9
224 && ndigits_total < MAX_STRING_DIGITS_128) {
225 buffer[ndigits_total] = c;
226 ps++;
227 c = *ps;
228 ndigits_total++;
230 ndigits_after = ndigits_total - ndigits_before;
233 } else {
234 // we encountered a radix point while detecting zeros
235 //if (c = *ps){
237 c = *ps;
238 ndigits_total = 0;
239 // investigate string (after radix point)
240 while ((unsigned) (c - '0') <= 9
241 && ndigits_total < MAX_STRING_DIGITS_128) {
242 buffer[ndigits_total] = c;
243 ps++;
244 c = *ps;
245 ndigits_total++;
247 ndigits_after = ndigits_total - ndigits_before;
250 // get exponent
251 dec_expon = 0;
252 if (ndigits_total < MAX_STRING_DIGITS_128) {
253 if (c) {
254 if (c != 'e' && c != 'E') {
255 // return NaN
256 res.w[1] = 0x7c00000000000000ull;
257 res.w[0] = 0;
258 BID_RETURN (res);
260 ps++;
261 c = *ps;
263 if (((unsigned) (c - '0') > 9)
264 && ((c != '+' && c != '-') || (unsigned) (ps[1] - '0') > 9)) {
265 // return NaN
266 res.w[1] = 0x7c00000000000000ull;
267 res.w[0] = 0;
268 BID_RETURN (res);
271 if (c == '-') {
272 sgn_exp = -1;
273 ps++;
274 c = *ps;
275 } else if (c == '+') {
276 ps++;
277 c = *ps;
280 dec_expon = c - '0';
281 i = 1;
282 ps++;
283 c = *ps - '0';
284 while (((unsigned) c) <= 9 && i < 7) {
285 d2 = dec_expon + dec_expon;
286 dec_expon = (d2 << 2) + d2 + c;
287 ps++;
288 c = *ps - '0';
289 i++;
293 dec_expon = (dec_expon + sgn_exp) ^ sgn_exp;
297 if (ndigits_total <= MAX_FORMAT_DIGITS_128) {
298 dec_expon +=
299 DECIMAL_EXPONENT_BIAS_128 - ndigits_after -
300 right_radix_leading_zeros;
301 if (dec_expon < 0) {
302 res.w[1] = 0 | sign_x;
303 res.w[0] = 0;
305 if (ndigits_total == 0) {
306 CX.w[0] = 0;
307 CX.w[1] = 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;
315 CX.w[1] = 0;
316 } else {
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';
323 i++;
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)
334 CX.w[1]++;
336 get_BID128_string (&res, sign_x, dec_expon, CX);
337 BID_RETURN (res);
338 } else {
339 // simply round using the digits that were read
341 dec_expon +=
342 ndigits_before + DECIMAL_EXPONENT_BIAS_128 -
343 MAX_FORMAT_DIGITS_128 - right_radix_leading_zeros;
345 if (dec_expon < 0) {
346 res.w[1] = 0 | sign_x;
347 res.w[0] = 0;
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';
356 i++;
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) {
364 carry = 0;
365 i++;
367 for (; i < ndigits_total; i++) {
368 if (buffer[i] > '0') {
369 carry = 1;
370 break;
374 // now form the coefficient as coeff_high*10^17+coeff_low+carry
375 scale_high = 100000000000000000ull;
376 if (dec_expon < 0) {
377 if (dec_expon > -MAX_FORMAT_DIGITS_128) {
378 scale_high = 1000000000000000000ull;
379 coeff_low = (coeff_low << 3) + (coeff_low << 1);
380 dec_expon--;
382 if (dec_expon == -MAX_FORMAT_DIGITS_128
383 && coeff_high > 50000000000000000ull)
384 carry = 0;
387 __mul_64x64_to_128_fast (CX, coeff_high, scale_high);
389 coeff_low += carry;
390 CX.w[0] += coeff_low;
391 if (CX.w[0] < coeff_low)
392 CX.w[1]++;
394 get_BID128_string (&res, sign_x, dec_expon, CX);
395 BID_RETURN (res);