Annotation of OpenXM_contrib/gmp/mpf/set_str.c, Revision 1.1.1.2
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.2 ! maekawa 5: Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000 Free Software Foundation,
! 6: 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:
25: #include <string.h>
26: #include <ctype.h>
27: #include "gmp.h"
28: #include "gmp-impl.h"
29: #include "longlong.h"
30:
1.1.1.2 ! maekawa 31:
1.1 maekawa 32: long int strtol _PROTO ((const char *, char **ptr, int));
33:
34: static int
1.1.1.2 ! maekawa 35: #if __STDC__
! 36: digit_value_in_base (int c, int base)
! 37: #else
1.1 maekawa 38: digit_value_in_base (c, base)
39: int c;
40: int base;
1.1.1.2 ! maekawa 41: #endif
1.1 maekawa 42: {
43: int digit;
44:
45: if (isdigit (c))
46: digit = c - '0';
47: else if (islower (c))
48: digit = c - 'a' + 10;
49: else if (isupper (c))
50: digit = c - 'A' + 10;
51: else
52: return -1;
53:
54: if (digit < base)
55: return digit;
56: return -1;
57: }
58:
59: int
60: #if __STDC__
61: mpf_set_str (mpf_ptr x, const char *str, int base)
62: #else
63: mpf_set_str (x, str, base)
64: mpf_ptr x;
65: char *str;
66: int base;
67: #endif
68: {
69: size_t str_size;
70: char *s, *begs;
71: size_t i;
72: mp_size_t xsize;
73: int c;
74: int negative;
75: char *dotpos = 0;
76: int expflag;
77: int decimal_exponent_flag;
78: TMP_DECL (marker);
79:
80: TMP_MARK (marker);
81:
82: c = *str;
83:
84: /* Skip whitespace. */
85: while (isspace (c))
86: c = *++str;
87:
88: negative = 0;
89: if (c == '-')
90: {
91: negative = 1;
92: c = *++str;
93: }
94:
95: decimal_exponent_flag = base < 0;
96: base = ABS (base);
97:
1.1.1.2 ! maekawa 98: if (digit_value_in_base (c, base == 0 ? 10 : base) < 0
! 99: && (c != '.' || digit_value_in_base (str[1], base == 0 ? 10 : base) < 0))
1.1 maekawa 100: return -1; /* error if no digits */
101:
102: /* If BASE is 0, try to find out the base by looking at the initial
103: characters. */
104: if (base == 0)
105: {
106: base = 10;
107: #if 0
108: if (c == '0')
109: {
110: base = 8;
1.1.1.2 ! maekawa 111: if (str[1] == 'x' || str[1] == 'X')
! 112: {
! 113: base = 16;
! 114: str += 2;
! 115: c = *str;
! 116: }
1.1 maekawa 117: }
118: #endif
119: }
120:
121: expflag = 0;
122: str_size = strlen (str);
123: for (i = 0; i < str_size; i++)
124: {
125: c = str[i];
126: if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
127: {
128: expflag = 1;
129: str_size = i;
130: break;
131: }
132:
133: }
134:
135: s = begs = (char *) TMP_ALLOC (str_size + 1);
136:
137: for (i = 0; i < str_size; i++)
138: {
139: c = *str;
140: if (!isspace (c))
141: {
142: int dig;
143:
144: if (c == '.')
145: {
146: if (dotpos != 0)
147: {
148: TMP_FREE (marker);
149: return -1;
150: }
151: dotpos = s;
152: }
153: else
154: {
155: dig = digit_value_in_base (c, base);
156: if (dig < 0)
157: {
158: TMP_FREE (marker);
159: return -1;
160: }
161: *s++ = dig;
162: }
163: }
164: c = *++str;
165: }
166:
167: str_size = s - begs;
168:
169: xsize = str_size / __mp_bases[base].chars_per_limb + 2;
170: {
171: long exp_in_base;
1.1.1.2 ! maekawa 172: mp_size_t ralloc, rsize, msize;
1.1 maekawa 173: int cnt, i;
1.1.1.2 ! maekawa 174: mp_ptr mp, tp, rp;
1.1 maekawa 175: mp_exp_t exp_in_limbs;
1.1.1.2 ! maekawa 176: mp_size_t prec = x->_mp_prec + 1;
1.1 maekawa 177: int divflag;
1.1.1.2 ! maekawa 178: mp_size_t madj, radj;
1.1 maekawa 179:
180: mp = (mp_ptr) TMP_ALLOC (xsize * BYTES_PER_MP_LIMB);
181: msize = mpn_set_str (mp, (unsigned char *) begs, str_size, base);
182:
183: if (msize == 0)
184: {
185: x->_mp_size = 0;
186: x->_mp_exp = 0;
187: TMP_FREE (marker);
188: return 0;
189: }
190:
1.1.1.2 ! maekawa 191: madj = 0;
! 192: /* Ignore excess limbs in MP,MSIZE. */
! 193: if (msize > prec)
! 194: {
! 195: madj = msize - prec;
! 196: mp += msize - prec;
! 197: msize = prec;
! 198: }
! 199:
1.1 maekawa 200: if (expflag != 0)
201: exp_in_base = strtol (str + 1, (char **) 0,
202: decimal_exponent_flag ? 10 : base);
203: else
204: exp_in_base = 0;
205: if (dotpos != 0)
206: exp_in_base -= s - dotpos;
207: divflag = exp_in_base < 0;
208: exp_in_base = ABS (exp_in_base);
209:
210: if (exp_in_base == 0)
211: {
212: MPN_COPY (x->_mp_d, mp, msize);
213: x->_mp_size = negative ? -msize : msize;
1.1.1.2 ! maekawa 214: x->_mp_exp = msize + madj;
1.1 maekawa 215: TMP_FREE (marker);
216: return 0;
217: }
218:
1.1.1.2 ! maekawa 219: radj = 0; /* counts number of ignored low limbs in r */
! 220:
! 221: ralloc = 2 * (prec + 1);
! 222: rp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
! 223: tp = (mp_ptr) TMP_ALLOC (ralloc * BYTES_PER_MP_LIMB);
1.1 maekawa 224:
225: rp[0] = base;
226: rsize = 1;
227: count_leading_zeros (cnt, exp_in_base);
228: for (i = BITS_PER_MP_LIMB - cnt - 2; i >= 0; i--)
229: {
230: mpn_mul_n (tp, rp, rp, rsize);
231: rsize = 2 * rsize;
232: rsize -= tp[rsize - 1] == 0;
1.1.1.2 ! maekawa 233: radj <<= 1;
! 234:
! 235: if (rsize > prec)
! 236: {
! 237: radj += rsize - prec;
! 238: MPN_COPY_INCR (rp, tp + rsize - prec, prec);
! 239: rsize = prec;
! 240: }
! 241: else
! 242: MP_PTR_SWAP (rp, tp);
1.1 maekawa 243:
244: if (((exp_in_base >> i) & 1) != 0)
245: {
1.1.1.2 ! maekawa 246: mp_limb_t cy;
1.1 maekawa 247: cy = mpn_mul_1 (rp, rp, rsize, (mp_limb_t) base);
248: rp[rsize] = cy;
249: rsize += cy != 0;
250: }
251: }
252:
253: if (rsize > prec)
254: {
1.1.1.2 ! maekawa 255: radj += rsize - prec;
1.1 maekawa 256: rp += rsize - prec;
257: rsize = prec;
258: }
1.1.1.2 ! maekawa 259:
1.1 maekawa 260: if (divflag)
261: {
262: mp_ptr qp;
1.1.1.2 ! maekawa 263: mp_limb_t qlimb;
! 264: if (msize < rsize)
1.1 maekawa 265: {
1.1.1.2 ! maekawa 266: /* Pad out MP,MSIZE for current divrem semantics. */
1.1 maekawa 267: mp_ptr tmp = (mp_ptr) TMP_ALLOC ((rsize + 1) * BYTES_PER_MP_LIMB);
268: MPN_ZERO (tmp, rsize - msize);
269: MPN_COPY (tmp + rsize - msize, mp, msize);
270: mp = tmp;
1.1.1.2 ! maekawa 271: madj -= rsize - msize;
1.1 maekawa 272: msize = rsize;
273: }
274: count_leading_zeros (cnt, rp[rsize - 1]);
275: if (cnt != 0)
276: {
1.1.1.2 ! maekawa 277: mp_limb_t cy;
1.1 maekawa 278: mpn_lshift (rp, rp, rsize, cnt);
279: cy = mpn_lshift (mp, mp, msize, cnt);
280: if (cy)
281: mp[msize++] = cy;
282: }
1.1.1.2 ! maekawa 283:
1.1 maekawa 284: qp = (mp_ptr) TMP_ALLOC ((prec + 1) * BYTES_PER_MP_LIMB);
1.1.1.2 ! maekawa 285: qlimb = mpn_divrem (qp, prec - (msize - rsize), mp, msize, rp, rsize);
1.1 maekawa 286: tp = qp;
1.1.1.2 ! maekawa 287: exp_in_limbs = qlimb + (msize - rsize) + (madj - radj);
! 288: rsize = prec;
! 289: if (qlimb != 0)
! 290: {
! 291: tp[prec] = qlimb;
! 292: /* Skip the least significant limb not to overrun the destination
! 293: variable. */
! 294: tp++;
! 295: }
1.1 maekawa 296: }
297: else
298: {
299: tp = (mp_ptr) TMP_ALLOC ((rsize + msize) * BYTES_PER_MP_LIMB);
300: if (rsize > msize)
301: mpn_mul (tp, rp, rsize, mp, msize);
302: else
303: mpn_mul (tp, mp, msize, rp, rsize);
304: rsize += msize;
305: rsize -= tp[rsize - 1] == 0;
1.1.1.2 ! maekawa 306: exp_in_limbs = rsize + madj + radj;
1.1 maekawa 307:
308: if (rsize > prec)
309: {
310: tp += rsize - prec;
311: rsize = prec;
312: exp_in_limbs += 0;
313: }
314: }
315:
316: MPN_COPY (x->_mp_d, tp, rsize);
317: x->_mp_size = negative ? -rsize : rsize;
318: x->_mp_exp = exp_in_limbs;
319: TMP_FREE (marker);
320: return 0;
321: }
322: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>