OSDN Git Service

Merged with libbbid branch at revision 126349.
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid128_fromstring.c
1 /* Copyright (C) 2007  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 2, or (at your option) any later
8 version.
9
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.)
18
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.
23
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.  */
28
29 #define BID_128RES
30 #include "bid_internal.h"
31
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
35
36
37 #if DECIMAL_CALL_BY_REFERENCE
38
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
44
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];
55
56 #if DECIMAL_CALL_BY_REFERENCE
57 #if !DECIMAL_GLOBAL_ROUNDING
58   _IDEC_round rnd_mode = *prnd_mode;
59 #endif
60 #endif
61
62   right_radix_leading_zeros = rdx_pt_enc = 0;
63
64   // if null string, return NaN
65   if (!ps) {
66     res.w[1] = 0x7c00000000000000ull;
67     res.w[0] = 0;
68     BID_RETURN (res);
69   }
70   // eliminate leading white space
71   while ((*ps == ' ') || (*ps == '\t'))
72     ps++;
73
74   // c gets first character
75   c = *ps;
76
77
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);
96     }
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);
107     }
108   }
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;
116
117     if (c == '+')
118       res.w[1] = 0x7800000000000000ull;
119     else if (c == '-')
120       res.w[1] = 0xf800000000000000ull;
121     else
122       res.w[1] = 0x7c00000000000000ull;
123
124     BID_RETURN (res);
125   }
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);
135   }
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;
141
142   // go to next character if leading sign
143   if (c == '-' || c == '+')
144     ps++;
145
146   c = *ps;
147
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);
153   }
154   // detect zero (and eliminate/ignore leading zeros)
155   if (*(ps) == '0') {
156
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') {
160
161       ps++;
162
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++;
167       }
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);
181           }
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);
188         }
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);
196       }
197     }
198   }
199
200   c = *ps;
201
202   // initialize local variables
203   ndigits_before = ndigits_after = ndigits_total = 0;
204   sgn_exp = 0;
205   // pstart_coefficient = ps;
206
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++;
215     }
216
217     ndigits_total = ndigits_before;
218     if (c == '.') {
219       ps++;
220       if ((c = *ps)) {
221
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++;
229         }
230         ndigits_after = ndigits_total - ndigits_before;
231       }
232     }
233   } else {
234     // we encountered a radix point while detecting zeros
235     //if (c = *ps){
236
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++;
246     }
247     ndigits_after = ndigits_total - ndigits_before;
248   }
249
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);
259       }
260       ps++;
261       c = *ps;
262
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);
269       }
270
271       if (c == '-') {
272         sgn_exp = -1;
273         ps++;
274         c = *ps;
275       } else if (c == '+') {
276         ps++;
277         c = *ps;
278       }
279
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++;
290       }
291     }
292
293     dec_expon = (dec_expon + sgn_exp) ^ sgn_exp;
294   }
295
296
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;
304     }
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';
313       }
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';
321       }
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';
327       }
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);
331
332       CX.w[0] += coeff_low;
333       if (CX.w[0] < coeff_low)
334         CX.w[1]++;
335     }
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
340
341     dec_expon +=
342       ndigits_before + DECIMAL_EXPONENT_BIAS_128 -
343       MAX_FORMAT_DIGITS_128 - right_radix_leading_zeros;
344
345     if (dec_expon < 0) {
346       res.w[1] = 0 | sign_x;
347       res.w[0] = 0;
348     }
349
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';
354     }
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';
360     }
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++;
366       }
367       for (; i < ndigits_total; i++) {
368         if (buffer[i] > '0') {
369           carry = 1;
370           break;
371         }
372       }
373     }
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--;
381       }
382       if (dec_expon == -MAX_FORMAT_DIGITS_128
383           && coeff_high > 50000000000000000ull)
384         carry = 0;
385     }
386
387     __mul_64x64_to_128_fast (CX, coeff_high, scale_high);
388
389     coeff_low += carry;
390     CX.w[0] += coeff_low;
391     if (CX.w[0] < coeff_low)
392       CX.w[1]++;
393
394     get_BID128_string (&res, sign_x, dec_expon, CX);
395     BID_RETURN (res);
396   }
397 }