xref: /dragonfly/contrib/gmp/mpf/set_str.c (revision d4ef6694)
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 (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 = 2 + (mp_size_t)
254       (str_size / (GMP_NUMB_BITS * mp_bases[base].chars_per_bit_exactly));
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 }
392