Merge branch 'vendor/GMP' into gcc441
[dragonfly.git] / contrib / gmp / mpf / set_str.c
1 /* mpf_set_str (dest, string, base) -- Convert the string STRING
2    in base BASE to a float in dest.  If BASE is zero, the leading characters
3    of STRING is used to figure out the base.
4
5 Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2005, 2007,
6 2008 Free Software Foundation, Inc.
7
8 This file is part of the GNU MP Library.
9
10 The GNU MP Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
14
15 The GNU MP Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
18 License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
22
23 /*
24   This still needs work, as suggested by some FIXME comments.
25   1. Don't depend on superfluous mantissa digits.
26   2. Allocate temp space more cleverly.
27   3. Use mpn_tdiv_qr instead of mpn_lshift+mpn_divrem.
28 */
29
30 #define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
31
32 #include "config.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #if HAVE_LANGINFO_H
39 #include <langinfo.h>  /* for nl_langinfo */
40 #endif
41
42 #if HAVE_LOCALE_H
43 #include <locale.h>    /* for localeconv */
44 #endif
45
46 #include "gmp.h"
47 #include "gmp-impl.h"
48 #include "longlong.h"
49
50 extern const unsigned char __gmp_digit_value_tab[];
51 #define digit_value_tab __gmp_digit_value_tab
52
53 /* Compute base^exp and return the most significant prec limbs in rp[].
54    Put the count of omitted low limbs in *ign.
55    Return the actual size (which might be less than prec).  */
56 static mp_size_t
57 mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
58                     mp_limb_t base, mp_exp_t exp,
59                     mp_size_t prec, mp_ptr tp)
60 {
61   mp_size_t ign;                /* counts number of ignored low limbs in r */
62   mp_size_t off;                /* keeps track of offset where value starts */
63   mp_ptr passed_rp = rp;
64   mp_size_t rn;
65   int cnt;
66   int i;
67
68   rp[0] = base;
69   rn = 1;
70   off = 0;
71   ign = 0;
72   count_leading_zeros (cnt, exp);
73   for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
74     {
75       mpn_sqr_n (tp, rp + off, rn);
76       rn = 2 * rn;
77       rn -= tp[rn - 1] == 0;
78       ign <<= 1;
79
80       off = 0;
81       if (rn > prec)
82         {
83           ign += rn - prec;
84           off = rn - prec;
85           rn = prec;
86         }
87       MP_PTR_SWAP (rp, tp);
88
89       if (((exp >> i) & 1) != 0)
90         {
91           mp_limb_t cy;
92           cy = mpn_mul_1 (rp, rp + off, rn, base);
93           rp[rn] = cy;
94           rn += cy != 0;
95           off = 0;
96         }
97     }
98
99   if (rn > prec)
100     {
101       ign += rn - prec;
102       rp += rn - prec;
103       rn = prec;
104     }
105
106   MPN_COPY_INCR (passed_rp, rp + off, rn);
107   *ignp = ign;
108   return rn;
109 }
110
111 int
112 mpf_set_str (mpf_ptr x, const char *str, int base)
113 {
114   size_t str_size;
115   char *s, *begs;
116   size_t i, j;
117   int c;
118   int negative;
119   char *dotpos = 0;
120   const char *expptr;
121   int exp_base;
122   const char  *point = GMP_DECIMAL_POINT;
123   size_t      pointlen = strlen (point);
124   const unsigned char *digit_value;
125   TMP_DECL;
126
127   c = (unsigned char) *str;
128
129   /* Skip whitespace.  */
130   while (isspace (c))
131     c = (unsigned char) *++str;
132
133   negative = 0;
134   if (c == '-')
135     {
136       negative = 1;
137       c = (unsigned char) *++str;
138     }
139
140   /* Default base to decimal.  */
141   if (base == 0)
142     base = 10;
143
144   exp_base = base;
145
146   if (base < 0)
147     {
148       exp_base = 10;
149       base = -base;
150     }
151
152   digit_value = digit_value_tab;
153   if (base > 36)
154     {
155       /* For bases > 36, use the collating sequence
156          0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
157       digit_value += 224;
158       if (base > 62)
159         return -1;              /* too large base */
160     }
161
162   /* Require at least one digit, possibly after an initial decimal point.  */
163   if (digit_value[c] >= (base == 0 ? 10 : base))
164     {
165       /* not a digit, must be a decimal point */
166       for (i = 0; i < pointlen; i++)
167         if (str[i] != point[i])
168           return -1;
169       if (digit_value[(unsigned char) str[pointlen]] >= (base == 0 ? 10 : base))
170         return -1;
171     }
172
173   /* Locate exponent part of the input.  Look from the right of the string,
174      since the exponent is usually a lot shorter than the mantissa.  */
175   expptr = NULL;
176   str_size = strlen (str);
177   for (i = str_size - 1; i > 0; i--)
178     {
179       c = (unsigned char) str[i];
180       if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
181         {
182           expptr = str + i + 1;
183           str_size = i;
184           break;
185         }
186     }
187
188   TMP_MARK;
189   s = begs = (char *) TMP_ALLOC (str_size + 1);
190
191   /* Loop through mantissa, converting it from ASCII to raw byte values.  */
192   for (i = 0; i < str_size; i++)
193     {
194       c = (unsigned char) *str;
195       if (!isspace (c))
196         {
197           int dig;
198
199           for (j = 0; j < pointlen; j++)
200             if (str[j] != point[j])
201               goto not_point;
202           if (1)
203             {
204               if (dotpos != 0)
205                 {
206                   /* already saw a decimal point, another is invalid */
207                   TMP_FREE;
208                   return -1;
209                 }
210               dotpos = s;
211               str += pointlen - 1;
212               i += pointlen - 1;
213             }
214           else
215             {
216             not_point:
217               dig = digit_value[c];
218               if (dig >= base)
219                 {
220                   TMP_FREE;
221                   return -1;
222                 }
223               *s++ = dig;
224             }
225         }
226       c = (unsigned char) *++str;
227     }
228
229   str_size = s - begs;
230
231   {
232     long exp_in_base;
233     mp_size_t ra, ma, rn, mn;
234     int cnt;
235     mp_ptr mp, tp, rp;
236     mp_exp_t exp_in_limbs;
237     mp_size_t prec = PREC(x) + 1;
238     int divflag;
239     mp_size_t madj, radj;
240
241 #if 0
242     size_t n_chars_needed;
243
244     /* This breaks things like 0.000...0001.  To safely ignore superfluous
245        digits, we need to skip over leading zeros.  */
246     /* Just consider the relevant leading digits of the mantissa.  */
247     n_chars_needed = 2 + (size_t)
248       (((size_t) prec * GMP_NUMB_BITS) * mp_bases[base].chars_per_bit_exactly);
249     if (str_size > n_chars_needed)
250       str_size = n_chars_needed;
251 #endif
252
253     ma = (((mp_size_t) (str_size / mp_bases[base].chars_per_bit_exactly))
254           / GMP_NUMB_BITS + 2);
255     mp = TMP_ALLOC_LIMBS (ma);
256     mn = mpn_set_str (mp, (unsigned char *) begs, str_size, base);
257
258     if (mn == 0)
259       {
260         SIZ(x) = 0;
261         EXP(x) = 0;
262         TMP_FREE;
263         return 0;
264       }
265
266     madj = 0;
267     /* Ignore excess limbs in MP,MSIZE.  */
268     if (mn > prec)
269       {
270         madj = mn - prec;
271         mp += mn - prec;
272         mn = prec;
273       }
274
275     if (expptr != 0)
276       {
277         /* Scan and convert the exponent, in base exp_base.  */
278         long dig, minus, plusminus;
279         c = (unsigned char) *expptr;
280         minus = -(long) (c == '-');
281         plusminus = minus | -(long) (c == '+');
282         expptr -= plusminus;                    /* conditional increment */
283         c = (unsigned char) *expptr++;
284         dig = digit_value[c];
285         if (dig >= exp_base)
286           {
287             TMP_FREE;
288             return -1;
289           }
290         exp_in_base = dig;
291         c = (unsigned char) *expptr++;
292         dig = digit_value[c];
293         while (dig < exp_base)
294           {
295             exp_in_base = exp_in_base * exp_base;
296             exp_in_base += dig;
297             c = (unsigned char) *expptr++;
298             dig = digit_value[c];
299           }
300         exp_in_base = (exp_in_base ^ minus) - minus; /* conditional negation */
301       }
302     else
303       exp_in_base = 0;
304     if (dotpos != 0)
305       exp_in_base -= s - dotpos;
306     divflag = exp_in_base < 0;
307     exp_in_base = ABS (exp_in_base);
308
309     if (exp_in_base == 0)
310       {
311         MPN_COPY (PTR(x), mp, mn);
312         SIZ(x) = negative ? -mn : mn;
313         EXP(x) = mn + madj;
314         TMP_FREE;
315         return 0;
316       }
317
318     ra = 2 * (prec + 1);
319     rp = TMP_ALLOC_LIMBS (ra);
320     tp = TMP_ALLOC_LIMBS (ra);
321     rn = mpn_pow_1_highpart (rp, &radj, (mp_limb_t) base, exp_in_base, prec, tp);
322
323     if (divflag)
324       {
325 #if 0
326         /* FIXME: Should use mpn_tdiv here.  */
327         mpn_tdiv_qr (qp, mp, 0L, mp, mn, rp, rn);
328 #else
329         mp_ptr qp;
330         mp_limb_t qlimb;
331         if (mn < rn)
332           {
333             /* Pad out MP,MSIZE for current divrem semantics.  */
334             mp_ptr tmp = TMP_ALLOC_LIMBS (rn + 1);
335             MPN_ZERO (tmp, rn - mn);
336             MPN_COPY (tmp + rn - mn, mp, mn);
337             mp = tmp;
338             madj -= rn - mn;
339             mn = rn;
340           }
341         if ((rp[rn - 1] & GMP_NUMB_HIGHBIT) == 0)
342           {
343             mp_limb_t cy;
344             count_leading_zeros (cnt, rp[rn - 1]);
345             cnt -= GMP_NAIL_BITS;
346             mpn_lshift (rp, rp, rn, cnt);
347             cy = mpn_lshift (mp, mp, mn, cnt);
348             if (cy)
349               mp[mn++] = cy;
350           }
351
352         qp = TMP_ALLOC_LIMBS (prec + 1);
353         qlimb = mpn_divrem (qp, prec - (mn - rn), mp, mn, rp, rn);
354         tp = qp;
355         exp_in_limbs = qlimb + (mn - rn) + (madj - radj);
356         rn = prec;
357         if (qlimb != 0)
358           {
359             tp[prec] = qlimb;
360             /* Skip the least significant limb not to overrun the destination
361                variable.  */
362             tp++;
363           }
364 #endif
365       }
366     else
367       {
368         tp = TMP_ALLOC_LIMBS (rn + mn);
369         if (rn > mn)
370           mpn_mul (tp, rp, rn, mp, mn);
371         else
372           mpn_mul (tp, mp, mn, rp, rn);
373         rn += mn;
374         rn -= tp[rn - 1] == 0;
375         exp_in_limbs = rn + madj + radj;
376
377         if (rn > prec)
378           {
379             tp += rn - prec;
380             rn = prec;
381             exp_in_limbs += 0;
382           }
383       }
384
385     MPN_COPY (PTR(x), tp, rn);
386     SIZ(x) = negative ? -rn : rn;
387     EXP(x) = exp_in_limbs;
388     TMP_FREE;
389     return 0;
390   }
391 }