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, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2005, 2007,
6 2008 Free Software 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 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.
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.
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/. */
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.
30 #define _GNU_SOURCE /* for DECIMAL_POINT in langinfo.h */
39 #include <langinfo.h> /* for nl_langinfo */
43 #include <locale.h> /* for localeconv */
50 extern const unsigned char __gmp_digit_value_tab[];
51 #define digit_value_tab __gmp_digit_value_tab
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). */
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)
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;
72 count_leading_zeros (cnt, exp);
73 for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
75 mpn_sqr_n (tp, rp + off, rn);
77 rn -= tp[rn - 1] == 0;
89 if (((exp >> i) & 1) != 0)
92 cy = mpn_mul_1 (rp, rp + off, rn, base);
106 MPN_COPY_INCR (passed_rp, rp + off, rn);
112 mpf_set_str (mpf_ptr x, const char *str, int base)
122 const char *point = GMP_DECIMAL_POINT;
123 size_t pointlen = strlen (point);
124 const unsigned char *digit_value;
127 c = (unsigned char) *str;
129 /* Skip whitespace. */
131 c = (unsigned char) *++str;
137 c = (unsigned char) *++str;
140 /* Default base to decimal. */
152 digit_value = digit_value_tab;
155 /* For bases > 36, use the collating sequence
156 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz. */
159 return -1; /* too large base */
162 /* Require at least one digit, possibly after an initial decimal point. */
163 if (digit_value[c] >= (base == 0 ? 10 : base))
165 /* not a digit, must be a decimal point */
166 for (i = 0; i < pointlen; i++)
167 if (str[i] != point[i])
169 if (digit_value[(unsigned char) str[pointlen]] >= (base == 0 ? 10 : base))
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. */
176 str_size = strlen (str);
177 for (i = str_size - 1; i > 0; i--)
179 c = (unsigned char) str[i];
180 if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
182 expptr = str + i + 1;
189 s = begs = (char *) TMP_ALLOC (str_size + 1);
191 /* Loop through mantissa, converting it from ASCII to raw byte values. */
192 for (i = 0; i < str_size; i++)
194 c = (unsigned char) *str;
199 for (j = 0; j < pointlen; j++)
200 if (str[j] != point[j])
206 /* already saw a decimal point, another is invalid */
217 dig = digit_value[c];
226 c = (unsigned char) *++str;
233 mp_size_t ra, ma, rn, mn;
236 mp_exp_t exp_in_limbs;
237 mp_size_t prec = PREC(x) + 1;
239 mp_size_t madj, radj;
242 size_t n_chars_needed;
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;
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);
267 /* Ignore excess limbs in MP,MSIZE. */
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];
291 c = (unsigned char) *expptr++;
292 dig = digit_value[c];
293 while (dig < exp_base)
295 exp_in_base = exp_in_base * exp_base;
297 c = (unsigned char) *expptr++;
298 dig = digit_value[c];
300 exp_in_base = (exp_in_base ^ minus) - minus; /* conditional negation */
305 exp_in_base -= s - dotpos;
306 divflag = exp_in_base < 0;
307 exp_in_base = ABS (exp_in_base);
309 if (exp_in_base == 0)
311 MPN_COPY (PTR(x), mp, mn);
312 SIZ(x) = negative ? -mn : mn;
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);
326 /* FIXME: Should use mpn_tdiv here. */
327 mpn_tdiv_qr (qp, mp, 0L, mp, mn, rp, rn);
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);
341 if ((rp[rn - 1] & GMP_NUMB_HIGHBIT) == 0)
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);
352 qp = TMP_ALLOC_LIMBS (prec + 1);
353 qlimb = mpn_divrem (qp, prec - (mn - rn), mp, mn, rp, rn);
355 exp_in_limbs = qlimb + (mn - rn) + (madj - radj);
360 /* Skip the least significant limb not to overrun the destination
368 tp = TMP_ALLOC_LIMBS (rn + mn);
370 mpn_mul (tp, rp, rn, mp, mn);
372 mpn_mul (tp, mp, mn, rp, rn);
374 rn -= tp[rn - 1] == 0;
375 exp_in_limbs = rn + madj + radj;
385 MPN_COPY (PTR(x), tp, rn);
386 SIZ(x) = negative ? -rn : rn;
387 EXP(x) = exp_in_limbs;