beta-0.89.2
[luatex.git] / source / libs / gmp / gmp-src / mpf / set_str.c
blob9053accadeb15c0a6b937aa3ed0a4022f1b47b9e
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.
5 Copyright 1993-1997, 2000-2003, 2005, 2007, 2008, 2011, 2013 Free Software
6 Foundation, Inc.
8 This file is part of the GNU MP Library.
10 The GNU MP Library is free software; you can redistribute it and/or modify
11 it under the terms of either:
13 * the GNU Lesser General Public License as published by the Free
14 Software Foundation; either version 3 of the License, or (at your
15 option) any later version.
19 * the GNU General Public License as published by the Free Software
20 Foundation; either version 2 of the License, or (at your option) any
21 later version.
23 or both in parallel, as here.
25 The GNU MP Library is distributed in the hope that it will be useful, but
26 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
27 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28 for more details.
30 You should have received copies of the GNU General Public License and the
31 GNU Lesser General Public License along with the GNU MP Library. If not,
32 see https://www.gnu.org/licenses/. */
35 This still needs work, as suggested by some FIXME comments.
36 1. Don't depend on superfluous mantissa digits.
37 2. Allocate temp space more cleverly.
38 3. Use mpn_div_q instead of mpn_lshift+mpn_divrem.
41 #define _GNU_SOURCE /* for DECIMAL_POINT in langinfo.h */
43 #include "config.h"
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
49 #if HAVE_LANGINFO_H
50 #include <langinfo.h> /* for nl_langinfo */
51 #endif
53 #if HAVE_LOCALE_H
54 #include <locale.h> /* for localeconv */
55 #endif
57 #include "gmp.h"
58 #include "gmp-impl.h"
59 #include "longlong.h"
62 #define digit_value_tab __gmp_digit_value_tab
64 /* Compute base^exp and return the most significant prec limbs in rp[].
65 Put the count of omitted low limbs in *ign.
66 Return the actual size (which might be less than prec). */
67 static mp_size_t
68 mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
69 mp_limb_t base, mp_exp_t exp,
70 mp_size_t prec, mp_ptr tp)
72 mp_size_t ign; /* counts number of ignored low limbs in r */
73 mp_size_t off; /* keeps track of offset where value starts */
74 mp_ptr passed_rp = rp;
75 mp_size_t rn;
76 int cnt;
77 int i;
79 rp[0] = base;
80 rn = 1;
81 off = 0;
82 ign = 0;
83 count_leading_zeros (cnt, exp);
84 for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
86 mpn_sqr (tp, rp + off, rn);
87 rn = 2 * rn;
88 rn -= tp[rn - 1] == 0;
89 ign <<= 1;
91 off = 0;
92 if (rn > prec)
94 ign += rn - prec;
95 off = rn - prec;
96 rn = prec;
98 MP_PTR_SWAP (rp, tp);
100 if (((exp >> i) & 1) != 0)
102 mp_limb_t cy;
103 cy = mpn_mul_1 (rp, rp + off, rn, base);
104 rp[rn] = cy;
105 rn += cy != 0;
106 off = 0;
110 if (rn > prec)
112 ign += rn - prec;
113 rp += rn - prec;
114 rn = prec;
117 MPN_COPY_INCR (passed_rp, rp + off, rn);
118 *ignp = ign;
119 return rn;
123 mpf_set_str (mpf_ptr x, const char *str, int base)
125 size_t str_size;
126 char *s, *begs;
127 size_t i, j;
128 int c;
129 int negative;
130 char *dotpos = 0;
131 const char *expptr;
132 int exp_base;
133 const char *point = GMP_DECIMAL_POINT;
134 size_t pointlen = strlen (point);
135 const unsigned char *digit_value;
136 TMP_DECL;
138 c = (unsigned char) *str;
140 /* Skip whitespace. */
141 while (isspace (c))
142 c = (unsigned char) *++str;
144 negative = 0;
145 if (c == '-')
147 negative = 1;
148 c = (unsigned char) *++str;
151 /* Default base to decimal. */
152 if (base == 0)
153 base = 10;
155 exp_base = base;
157 if (base < 0)
159 exp_base = 10;
160 base = -base;
163 digit_value = digit_value_tab;
164 if (base > 36)
166 /* For bases > 36, use the collating sequence
167 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz. */
168 digit_value += 208;
169 if (base > 62)
170 return -1; /* too large base */
173 /* Require at least one digit, possibly after an initial decimal point. */
174 if (digit_value[c] >= base)
176 /* not a digit, must be a decimal point */
177 for (i = 0; i < pointlen; i++)
178 if (str[i] != point[i])
179 return -1;
180 if (digit_value[(unsigned char) str[pointlen]] >= base)
181 return -1;
184 /* Locate exponent part of the input. Look from the right of the string,
185 since the exponent is usually a lot shorter than the mantissa. */
186 expptr = NULL;
187 str_size = strlen (str);
188 for (i = str_size - 1; i > 0; i--)
190 c = (unsigned char) str[i];
191 if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
193 expptr = str + i + 1;
194 str_size = i;
195 break;
199 TMP_MARK;
200 s = begs = (char *) TMP_ALLOC (str_size + 1);
202 /* Loop through mantissa, converting it from ASCII to raw byte values. */
203 for (i = 0; i < str_size; i++)
205 c = (unsigned char) *str;
206 if (!isspace (c))
208 int dig;
210 for (j = 0; j < pointlen; j++)
211 if (str[j] != point[j])
212 goto not_point;
213 if (1)
215 if (dotpos != 0)
217 /* already saw a decimal point, another is invalid */
218 TMP_FREE;
219 return -1;
221 dotpos = s;
222 str += pointlen - 1;
223 i += pointlen - 1;
225 else
227 not_point:
228 dig = digit_value[c];
229 if (dig >= base)
231 TMP_FREE;
232 return -1;
234 *s++ = dig;
237 c = (unsigned char) *++str;
240 str_size = s - begs;
243 long exp_in_base;
244 mp_size_t ra, ma, rn, mn;
245 int cnt;
246 mp_ptr mp, tp, rp;
247 mp_exp_t exp_in_limbs;
248 mp_size_t prec = PREC(x) + 1;
249 int divflag;
250 mp_size_t madj, radj;
252 #if 0
253 size_t n_chars_needed;
255 /* This breaks things like 0.000...0001. To safely ignore superfluous
256 digits, we need to skip over leading zeros. */
257 /* Just consider the relevant leading digits of the mantissa. */
258 LIMBS_PER_DIGIT_IN_BASE (n_chars_needed, prec, base);
259 if (str_size > n_chars_needed)
260 str_size = n_chars_needed;
261 #endif
263 LIMBS_PER_DIGIT_IN_BASE (ma, str_size, base);
264 mp = TMP_ALLOC_LIMBS (ma);
265 mn = mpn_set_str (mp, (unsigned char *) begs, str_size, base);
267 if (mn == 0)
269 SIZ(x) = 0;
270 EXP(x) = 0;
271 TMP_FREE;
272 return 0;
275 madj = 0;
276 /* Ignore excess limbs in MP,MSIZE. */
277 if (mn > prec)
279 madj = mn - prec;
280 mp += mn - prec;
281 mn = prec;
284 if (expptr != 0)
286 /* Scan and convert the exponent, in base exp_base. */
287 long dig, minus, plusminus;
288 c = (unsigned char) *expptr;
289 minus = -(long) (c == '-');
290 plusminus = minus | -(long) (c == '+');
291 expptr -= plusminus; /* conditional increment */
292 c = (unsigned char) *expptr++;
293 dig = digit_value[c];
294 if (dig >= exp_base)
296 TMP_FREE;
297 return -1;
299 exp_in_base = dig;
300 c = (unsigned char) *expptr++;
301 dig = digit_value[c];
302 while (dig < exp_base)
304 exp_in_base = exp_in_base * exp_base;
305 exp_in_base += dig;
306 c = (unsigned char) *expptr++;
307 dig = digit_value[c];
309 exp_in_base = (exp_in_base ^ minus) - minus; /* conditional negation */
311 else
312 exp_in_base = 0;
313 if (dotpos != 0)
314 exp_in_base -= s - dotpos;
315 divflag = exp_in_base < 0;
316 exp_in_base = ABS (exp_in_base);
318 if (exp_in_base == 0)
320 MPN_COPY (PTR(x), mp, mn);
321 SIZ(x) = negative ? -mn : mn;
322 EXP(x) = mn + madj;
323 TMP_FREE;
324 return 0;
327 ra = 2 * (prec + 1);
328 rp = TMP_ALLOC_LIMBS (ra);
329 tp = TMP_ALLOC_LIMBS (ra);
330 rn = mpn_pow_1_highpart (rp, &radj, (mp_limb_t) base, exp_in_base, prec, tp);
332 if (divflag)
334 #if 0
335 /* FIXME: Should use mpn_div_q here. */
337 mpn_div_q (tp, mp, mn, rp, rn, scratch);
339 #else
340 mp_ptr qp;
341 mp_limb_t qlimb;
342 if (mn < rn)
344 /* Pad out MP,MSIZE for current divrem semantics. */
345 mp_ptr tmp = TMP_ALLOC_LIMBS (rn + 1);
346 MPN_ZERO (tmp, rn - mn);
347 MPN_COPY (tmp + rn - mn, mp, mn);
348 mp = tmp;
349 madj -= rn - mn;
350 mn = rn;
352 if ((rp[rn - 1] & GMP_NUMB_HIGHBIT) == 0)
354 mp_limb_t cy;
355 count_leading_zeros (cnt, rp[rn - 1]);
356 cnt -= GMP_NAIL_BITS;
357 mpn_lshift (rp, rp, rn, cnt);
358 cy = mpn_lshift (mp, mp, mn, cnt);
359 if (cy)
360 mp[mn++] = cy;
363 qp = TMP_ALLOC_LIMBS (prec + 1);
364 qlimb = mpn_divrem (qp, prec - (mn - rn), mp, mn, rp, rn);
365 tp = qp;
366 exp_in_limbs = qlimb + (mn - rn) + (madj - radj);
367 rn = prec;
368 if (qlimb != 0)
370 tp[prec] = qlimb;
371 /* Skip the least significant limb not to overrun the destination
372 variable. */
373 tp++;
375 #endif
377 else
379 tp = TMP_ALLOC_LIMBS (rn + mn);
380 if (rn > mn)
381 mpn_mul (tp, rp, rn, mp, mn);
382 else
383 mpn_mul (tp, mp, mn, rp, rn);
384 rn += mn;
385 rn -= tp[rn - 1] == 0;
386 exp_in_limbs = rn + madj + radj;
388 if (rn > prec)
390 tp += rn - prec;
391 rn = prec;
392 exp_in_limbs += 0;
396 MPN_COPY (PTR(x), tp, rn);
397 SIZ(x) = negative ? -rn : rn;
398 EXP(x) = exp_in_limbs;
399 TMP_FREE;
400 return 0;