Annotation of OpenXM_contrib/gmp/mpf/set_str.c, Revision 1.1.1.3
1.1 maekawa 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:
1.1.1.3 ! ohara 5: Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002 Free Software
! 6: Foundation, Inc.
1.1 maekawa 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
1.1.1.2 maekawa 11: it under the terms of the GNU Lesser General Public License as published by
12: the Free Software Foundation; either version 2.1 of the License, or (at your
1.1 maekawa 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
1.1.1.2 maekawa 17: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
1.1 maekawa 18: License for more details.
19:
1.1.1.2 maekawa 20: You should have received a copy of the GNU Lesser General Public License
1.1 maekawa 21: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
22: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23: MA 02111-1307, USA. */
24:
1.1.1.3 ! ohara 25: #include "config.h"
! 26:
! 27: #include <stdlib.h>
1.1 maekawa 28: #include <string.h>
29: #include <ctype.h>
1.1.1.3 ! ohara 30:
! 31: #if HAVE_LOCALE_H
! 32: #include <locale.h> /* for localeconv */
! 33: #endif
! 34:
1.1 maekawa 35: #include "gmp.h"
36: #include "gmp-impl.h"
37: #include "longlong.h"
38:
39: static int
1.1.1.2 maekawa 40: digit_value_in_base (int c, int base)
1.1 maekawa 41: {
42: int digit;
43:
44: if (isdigit (c))
45: digit = c - '0';
46: else if (islower (c))
47: digit = c - 'a' + 10;
48: else if (isupper (c))
49: digit = c - 'A' + 10;
50: else
51: return -1;
52:
53: if (digit < base)
54: return digit;
55: return -1;
56: }
57:
1.1.1.3 ! ohara 58: #if HAVE_LOCALECONV
! 59: /* Avoid memcmp for the usual case that point is one character. Don't
! 60: bother with str+1,point+1,pointlen-1 since those offsets would add to the
! 61: code size. */
! 62: #define POINTCMP_FAST(c, str) \
! 63: ((c) == point0 \
! 64: && (pointlen == 1 || memcmp (str, point, pointlen) == 0))
! 65: #define POINTCMP_SMALL(c, str) (memcmp (str, point, pointlen) == 0)
! 66: #define POINTLEN (pointlen)
1.1 maekawa 67: #else
1.1.1.3 ! ohara 68: #define POINTCMP_FAST(c, str) ((c) == '.')
! 69: #define POINTCMP_SMALL(c, str) ((c) == '.')
! 70: #define POINTLEN 1
1.1 maekawa 71: #endif
1.1.1.3 ! ohara 72:
! 73: int
! 74: mpf_set_str (mpf_ptr x, const char *str, int base)
1.1 maekawa 75: {
76: size_t str_size;
77: char *s, *begs;
78: size_t i;
79: mp_size_t xsize;
80: int c;
81: int negative;
82: char *dotpos = 0;
83: int expflag;
84: int decimal_exponent_flag;
1.1.1.3 ! ohara 85: #if HAVE_LOCALECONV
! 86: const char *point = localeconv()->decimal_point;
! 87: size_t pointlen = strlen (point);
! 88: int point0 = point[0];
! 89: #endif
1.1 maekawa 90: TMP_DECL (marker);
91:
92: TMP_MARK (marker);
93:
94: c = *str;
95:
96: /* Skip whitespace. */
97: while (isspace (c))
98: c = *++str;
99:
100: negative = 0;
101: if (c == '-')
102: {
103: negative = 1;
104: c = *++str;
105: }
106:
107: decimal_exponent_flag = base < 0;
108: base = ABS (base);
109:
1.1.1.3 ! ohara 110: /* require at least one digit, possibly after an initial decimal point */
! 111: if (digit_value_in_base (c, base == 0 ? 10 : base) < 0)
! 112: {
! 113: if (! POINTCMP_SMALL (c, str))
! 114: return -1;
! 115: if (digit_value_in_base (str[POINTLEN], base == 0 ? 10 : base) < 0)
! 116: return -1;
! 117: }
1.1 maekawa 118:
119: /* If BASE is 0, try to find out the base by looking at the initial
120: characters. */
121: if (base == 0)
122: {
123: base = 10;
124: #if 0
125: if (c == '0')
126: {
127: base = 8;
1.1.1.2 maekawa 128: if (str[1] == 'x' || str[1] == 'X')
129: {
130: base = 16;
131: str += 2;
132: c = *str;
133: }
1.1 maekawa 134: }
135: #endif
136: }
137:
138: expflag = 0;
139: str_size = strlen (str);
140: for (i = 0; i < str_size; i++)
141: {
142: c = str[i];
143: if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
144: {
145: expflag = 1;
146: str_size = i;
147: break;
148: }
149:
150: }
151:
152: s = begs = (char *) TMP_ALLOC (str_size + 1);
153:
154: for (i = 0; i < str_size; i++)
155: {
156: c = *str;
157: if (!isspace (c))
158: {
159: int dig;
160:
1.1.1.3 ! ohara 161: if (POINTCMP_FAST (c, str))
! 162: {
1.1 maekawa 163: if (dotpos != 0)
164: {
165: TMP_FREE (marker);
166: return -1;
167: }
168: dotpos = s;
1.1.1.3 ! ohara 169: str += POINTLEN - 1;
! 170: i += POINTLEN - 1;
1.1 maekawa 171: }
172: else
173: {
174: dig = digit_value_in_base (c, base);
175: if (dig < 0)
176: {
177: TMP_FREE (marker);
178: return -1;
179: }
180: *s++ = dig;
181: }
182: }
183: c = *++str;
184: }
185:
186: str_size = s - begs;
187:
188: xsize = str_size / __mp_bases[base].chars_per_limb + 2;
189: {
190: long exp_in_base;
1.1.1.2 maekawa 191: mp_size_t ralloc, rsize, msize;
1.1 maekawa 192: int cnt, i;
1.1.1.2 maekawa 193: mp_ptr mp, tp, rp;
1.1 maekawa 194: mp_exp_t exp_in_limbs;
1.1.1.2 maekawa 195: mp_size_t prec = x->_mp_prec + 1;
1.1 maekawa 196: int divflag;
1.1.1.2 maekawa 197: mp_size_t madj, radj;
1.1 maekawa 198:
199: mp = (mp_ptr) TMP_ALLOC (xsize * BYTES_PER_MP_LIMB);
200: msize = mpn_set_str (mp, (unsigned char *) begs, str_size, base);
201:
202: if (msize == 0)
203: {
204: x->_mp_size = 0;
205: x->_mp_exp = 0;
206: TMP_FREE (marker);
207: return 0;
208: }
209:
1.1.1.2 maekawa 210: madj = 0;
211: /* Ignore excess limbs in MP,MSIZE. */
212: if (msize > prec)
213: {
214: madj = msize - prec;
215: mp += msize - prec;
216: msize = prec;
217: }
218:
1.1 maekawa 219: if (expflag != 0)
220: exp_in_base = strtol (str + 1, (char **) 0,
221: decimal_exponent_flag ? 10 : base);
222: else
223: exp_in_base = 0;
224: if (dotpos != 0)
225: exp_in_base -= s - dotpos;
226: divflag = exp_in_base < 0;
227: exp_in_base = ABS (exp_in_base);
228:
229: if (exp_in_base == 0)
230: {
231: MPN_COPY (x->_mp_d, mp, msize);
232: x->_mp_size = negative ? -msize : msize;
1.1.1.2 maekawa 233: x->_mp_exp = msize + madj;
1.1 maekawa 234: TMP_FREE (marker);
235: return 0;
236: }
237:
1.1.1.2 maekawa 238: radj = 0; /* counts number of ignored low limbs in r */
239:
240: ralloc = 2 * (prec + 1);
241: rp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
242: tp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
1.1 maekawa 243:
244: rp[0] = base;
245: rsize = 1;
246: count_leading_zeros (cnt, exp_in_base);
1.1.1.3 ! ohara 247: for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
1.1 maekawa 248: {
1.1.1.3 ! ohara 249: mpn_sqr_n (tp, rp, rsize);
1.1 maekawa 250: rsize = 2 * rsize;
251: rsize -= tp[rsize - 1] == 0;
1.1.1.2 maekawa 252: radj <<= 1;
253:
254: if (rsize > prec)
255: {
256: radj += rsize - prec;
257: MPN_COPY_INCR (rp, tp + rsize - prec, prec);
258: rsize = prec;
259: }
260: else
261: MP_PTR_SWAP (rp, tp);
1.1 maekawa 262:
263: if (((exp_in_base >> i) & 1) != 0)
264: {
1.1.1.2 maekawa 265: mp_limb_t cy;
1.1 maekawa 266: cy = mpn_mul_1 (rp, rp, rsize, (mp_limb_t) base);
267: rp[rsize] = cy;
268: rsize += cy != 0;
269: }
270: }
271:
272: if (rsize > prec)
273: {
1.1.1.2 maekawa 274: radj += rsize - prec;
1.1 maekawa 275: rp += rsize - prec;
276: rsize = prec;
277: }
1.1.1.2 maekawa 278:
1.1 maekawa 279: if (divflag)
280: {
281: mp_ptr qp;
1.1.1.2 maekawa 282: mp_limb_t qlimb;
283: if (msize < rsize)
1.1 maekawa 284: {
1.1.1.2 maekawa 285: /* Pad out MP,MSIZE for current divrem semantics. */
1.1 maekawa 286: mp_ptr tmp = (mp_ptr) TMP_ALLOC ((rsize + 1) * BYTES_PER_MP_LIMB);
287: MPN_ZERO (tmp, rsize - msize);
288: MPN_COPY (tmp + rsize - msize, mp, msize);
289: mp = tmp;
1.1.1.2 maekawa 290: madj -= rsize - msize;
1.1 maekawa 291: msize = rsize;
292: }
1.1.1.3 ! ohara 293: if ((rp[rsize - 1] & GMP_NUMB_HIGHBIT) == 0)
1.1 maekawa 294: {
1.1.1.2 maekawa 295: mp_limb_t cy;
1.1.1.3 ! ohara 296: count_leading_zeros (cnt, rp[rsize - 1]);
! 297: cnt -= GMP_NAIL_BITS;
1.1 maekawa 298: mpn_lshift (rp, rp, rsize, cnt);
299: cy = mpn_lshift (mp, mp, msize, cnt);
300: if (cy)
301: mp[msize++] = cy;
302: }
1.1.1.2 maekawa 303:
1.1 maekawa 304: qp = (mp_ptr) TMP_ALLOC ((prec + 1) * BYTES_PER_MP_LIMB);
1.1.1.2 maekawa 305: qlimb = mpn_divrem (qp, prec - (msize - rsize), mp, msize, rp, rsize);
1.1 maekawa 306: tp = qp;
1.1.1.2 maekawa 307: exp_in_limbs = qlimb + (msize - rsize) + (madj - radj);
308: rsize = prec;
309: if (qlimb != 0)
310: {
311: tp[prec] = qlimb;
312: /* Skip the least significant limb not to overrun the destination
313: variable. */
314: tp++;
315: }
1.1 maekawa 316: }
317: else
318: {
319: tp = (mp_ptr) TMP_ALLOC ((rsize + msize) * BYTES_PER_MP_LIMB);
320: if (rsize > msize)
321: mpn_mul (tp, rp, rsize, mp, msize);
322: else
323: mpn_mul (tp, mp, msize, rp, rsize);
324: rsize += msize;
325: rsize -= tp[rsize - 1] == 0;
1.1.1.2 maekawa 326: exp_in_limbs = rsize + madj + radj;
1.1 maekawa 327:
328: if (rsize > prec)
329: {
330: tp += rsize - prec;
331: rsize = prec;
332: exp_in_limbs += 0;
333: }
334: }
335:
336: MPN_COPY (x->_mp_d, tp, rsize);
337: x->_mp_size = negative ? -rsize : rsize;
338: x->_mp_exp = exp_in_limbs;
339: TMP_FREE (marker);
340: return 0;
341: }
342: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>