github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpf/set_str.c (about) 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-1997, 2000-2003, 2005, 2007, 2008, 2011, 2013 Free Software 6 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 either: 12 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. 16 17 or 18 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. 22 23 or both in parallel, as here. 24 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. 29 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/. */ 33 34 /* 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. 39 */ 40 41 #define _GNU_SOURCE /* for DECIMAL_POINT in langinfo.h */ 42 43 #include "config.h" 44 45 #include <stdlib.h> 46 #include <string.h> 47 #include <ctype.h> 48 49 #if HAVE_LANGINFO_H 50 #include <langinfo.h> /* for nl_langinfo */ 51 #endif 52 53 #if HAVE_LOCALE_H 54 #include <locale.h> /* for localeconv */ 55 #endif 56 57 #include "gmp.h" 58 #include "gmp-impl.h" 59 #include "longlong.h" 60 61 62 #define digit_value_tab __gmp_digit_value_tab 63 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) 71 { 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; 78 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--) 85 { 86 mpn_sqr (tp, rp + off, rn); 87 rn = 2 * rn; 88 rn -= tp[rn - 1] == 0; 89 ign <<= 1; 90 91 off = 0; 92 if (rn > prec) 93 { 94 ign += rn - prec; 95 off = rn - prec; 96 rn = prec; 97 } 98 MP_PTR_SWAP (rp, tp); 99 100 if (((exp >> i) & 1) != 0) 101 { 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; 107 } 108 } 109 110 if (rn > prec) 111 { 112 ign += rn - prec; 113 rp += rn - prec; 114 rn = prec; 115 } 116 117 MPN_COPY_INCR (passed_rp, rp + off, rn); 118 *ignp = ign; 119 return rn; 120 } 121 122 int 123 mpf_set_str (mpf_ptr x, const char *str, int base) 124 { 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; 137 138 c = (unsigned char) *str; 139 140 /* Skip whitespace. */ 141 while (isspace (c)) 142 c = (unsigned char) *++str; 143 144 negative = 0; 145 if (c == '-') 146 { 147 negative = 1; 148 c = (unsigned char) *++str; 149 } 150 151 /* Default base to decimal. */ 152 if (base == 0) 153 base = 10; 154 155 exp_base = base; 156 157 if (base < 0) 158 { 159 exp_base = 10; 160 base = -base; 161 } 162 163 digit_value = digit_value_tab; 164 if (base > 36) 165 { 166 /* For bases > 36, use the collating sequence 167 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz. */ 168 digit_value += 208; 169 if (base > 62) 170 return -1; /* too large base */ 171 } 172 173 /* Require at least one digit, possibly after an initial decimal point. */ 174 if (digit_value[c] >= base) 175 { 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; 182 } 183 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--) 189 { 190 c = (unsigned char) str[i]; 191 if (c == '@' || (base <= 10 && (c == 'e' || c == 'E'))) 192 { 193 expptr = str + i + 1; 194 str_size = i; 195 break; 196 } 197 } 198 199 TMP_MARK; 200 s = begs = (char *) TMP_ALLOC (str_size + 1); 201 202 /* Loop through mantissa, converting it from ASCII to raw byte values. */ 203 for (i = 0; i < str_size; i++) 204 { 205 c = (unsigned char) *str; 206 if (!isspace (c)) 207 { 208 int dig; 209 210 for (j = 0; j < pointlen; j++) 211 if (str[j] != point[j]) 212 goto not_point; 213 if (1) 214 { 215 if (dotpos != 0) 216 { 217 /* already saw a decimal point, another is invalid */ 218 TMP_FREE; 219 return -1; 220 } 221 dotpos = s; 222 str += pointlen - 1; 223 i += pointlen - 1; 224 } 225 else 226 { 227 not_point: 228 dig = digit_value[c]; 229 if (dig >= base) 230 { 231 TMP_FREE; 232 return -1; 233 } 234 *s++ = dig; 235 } 236 } 237 c = (unsigned char) *++str; 238 } 239 240 str_size = s - begs; 241 242 { 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; 251 252 #if 0 253 size_t n_chars_needed; 254 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 262 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); 266 267 if (mn == 0) 268 { 269 SIZ(x) = 0; 270 EXP(x) = 0; 271 TMP_FREE; 272 return 0; 273 } 274 275 madj = 0; 276 /* Ignore excess limbs in MP,MSIZE. */ 277 if (mn > prec) 278 { 279 madj = mn - prec; 280 mp += mn - prec; 281 mn = prec; 282 } 283 284 if (expptr != 0) 285 { 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) 295 { 296 TMP_FREE; 297 return -1; 298 } 299 exp_in_base = dig; 300 c = (unsigned char) *expptr++; 301 dig = digit_value[c]; 302 while (dig < exp_base) 303 { 304 exp_in_base = exp_in_base * exp_base; 305 exp_in_base += dig; 306 c = (unsigned char) *expptr++; 307 dig = digit_value[c]; 308 } 309 exp_in_base = (exp_in_base ^ minus) - minus; /* conditional negation */ 310 } 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); 317 318 if (exp_in_base == 0) 319 { 320 MPN_COPY (PTR(x), mp, mn); 321 SIZ(x) = negative ? -mn : mn; 322 EXP(x) = mn + madj; 323 TMP_FREE; 324 return 0; 325 } 326 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); 331 332 if (divflag) 333 { 334 #if 0 335 /* FIXME: Should use mpn_div_q here. */ 336 ... 337 mpn_div_q (tp, mp, mn, rp, rn, scratch); 338 ... 339 #else 340 mp_ptr qp; 341 mp_limb_t qlimb; 342 if (mn < rn) 343 { 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; 351 } 352 if ((rp[rn - 1] & GMP_NUMB_HIGHBIT) == 0) 353 { 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; 361 } 362 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) 369 { 370 tp[prec] = qlimb; 371 /* Skip the least significant limb not to overrun the destination 372 variable. */ 373 tp++; 374 } 375 #endif 376 } 377 else 378 { 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; 387 388 if (rn > prec) 389 { 390 tp += rn - prec; 391 rn = prec; 392 exp_in_limbs += 0; 393 } 394 } 395 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; 401 } 402 }