strtod.c (8562B)
1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ 2 #include <stdlib.h> 3 #include <math.h> 4 #include <ctype.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <errno.h> 8 #include "plan9.h" 9 #include "fmt.h" 10 #include "fmtdef.h" 11 12 static ulong 13 umuldiv(ulong a, ulong b, ulong c) 14 { 15 double d; 16 17 d = ((double)a * (double)b) / (double)c; 18 if(d >= 4294967295.) 19 d = 4294967295.; 20 return (ulong)d; 21 } 22 23 /* 24 * This routine will convert to arbitrary precision 25 * floating point entirely in multi-precision fixed. 26 * The answer is the closest floating point number to 27 * the given decimal number. Exactly half way are 28 * rounded ala ieee rules. 29 * Method is to scale input decimal between .500 and .999... 30 * with external power of 2, then binary search for the 31 * closest mantissa to this decimal number. 32 * Nmant is is the required precision. (53 for ieee dp) 33 * Nbits is the max number of bits/word. (must be <= 28) 34 * Prec is calculated - the number of words of fixed mantissa. 35 */ 36 enum 37 { 38 Nbits = 28, /* bits safely represented in a ulong */ 39 Nmant = 53, /* bits of precision required */ 40 Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */ 41 Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */ 42 Ndig = 1500, 43 One = (ulong)(1<<Nbits), 44 Half = (ulong)(One>>1), 45 Maxe = 310, 46 47 Fsign = 1<<0, /* found - */ 48 Fesign = 1<<1, /* found e- */ 49 Fdpoint = 1<<2, /* found . */ 50 51 S0 = 0, /* _ _S0 +S1 #S2 .S3 */ 52 S1, /* _+ #S2 .S3 */ 53 S2, /* _+# #S2 .S4 eS5 */ 54 S3, /* _+. #S4 */ 55 S4, /* _+#.# #S4 eS5 */ 56 S5, /* _+#.#e +S6 #S7 */ 57 S6, /* _+#.#e+ #S7 */ 58 S7 /* _+#.#e+# #S7 */ 59 }; 60 61 static int xcmp(char*, char*); 62 static int fpcmp(char*, ulong*); 63 static void frnorm(ulong*); 64 static void divascii(char*, int*, int*, int*); 65 static void mulascii(char*, int*, int*, int*); 66 67 typedef struct Tab Tab; 68 struct Tab 69 { 70 int bp; 71 int siz; 72 char* cmp; 73 }; 74 75 double 76 fmtstrtod(const char *as, char **aas) 77 { 78 int na, ex, dp, bp, c, i, flag, state; 79 ulong low[Prec], hig[Prec], mid[Prec]; 80 double d; 81 char *s, a[Ndig]; 82 83 flag = 0; /* Fsign, Fesign, Fdpoint */ 84 na = 0; /* number of digits of a[] */ 85 dp = 0; /* na of decimal point */ 86 ex = 0; /* exonent */ 87 88 state = S0; 89 for(s=(char*)as;; s++) { 90 c = *s; 91 if(c >= '0' && c <= '9') { 92 switch(state) { 93 case S0: 94 case S1: 95 case S2: 96 state = S2; 97 break; 98 case S3: 99 case S4: 100 state = S4; 101 break; 102 103 case S5: 104 case S6: 105 case S7: 106 state = S7; 107 ex = ex*10 + (c-'0'); 108 continue; 109 } 110 if(na == 0 && c == '0') { 111 dp--; 112 continue; 113 } 114 if(na < Ndig-50) 115 a[na++] = c; 116 continue; 117 } 118 switch(c) { 119 case '\t': 120 case '\n': 121 case '\v': 122 case '\f': 123 case '\r': 124 case ' ': 125 if(state == S0) 126 continue; 127 break; 128 case '-': 129 if(state == S0) 130 flag |= Fsign; 131 else 132 flag |= Fesign; 133 case '+': 134 if(state == S0) 135 state = S1; 136 else 137 if(state == S5) 138 state = S6; 139 else 140 break; /* syntax */ 141 continue; 142 case '.': 143 flag |= Fdpoint; 144 dp = na; 145 if(state == S0 || state == S1) { 146 state = S3; 147 continue; 148 } 149 if(state == S2) { 150 state = S4; 151 continue; 152 } 153 break; 154 case 'e': 155 case 'E': 156 if(state == S2 || state == S4) { 157 state = S5; 158 continue; 159 } 160 break; 161 } 162 break; 163 } 164 165 /* 166 * clean up return char-pointer 167 */ 168 switch(state) { 169 case S0: 170 if(xcmp(s, "nan") == 0) { 171 if(aas != nil) 172 *aas = s+3; 173 goto retnan; 174 } 175 case S1: 176 if(xcmp(s, "infinity") == 0) { 177 if(aas != nil) 178 *aas = s+8; 179 goto retinf; 180 } 181 if(xcmp(s, "inf") == 0) { 182 if(aas != nil) 183 *aas = s+3; 184 goto retinf; 185 } 186 case S3: 187 if(aas != nil) 188 *aas = (char*)as; 189 goto ret0; /* no digits found */ 190 case S6: 191 s--; /* back over +- */ 192 case S5: 193 s--; /* back over e */ 194 break; 195 } 196 if(aas != nil) 197 *aas = s; 198 199 if(flag & Fdpoint) 200 while(na > 0 && a[na-1] == '0') 201 na--; 202 if(na == 0) 203 goto ret0; /* zero */ 204 a[na] = 0; 205 if(!(flag & Fdpoint)) 206 dp = na; 207 if(flag & Fesign) 208 ex = -ex; 209 dp += ex; 210 if(dp < -Maxe){ 211 errno = ERANGE; 212 goto ret0; /* underflow by exp */ 213 } else 214 if(dp > +Maxe) 215 goto retinf; /* overflow by exp */ 216 217 /* 218 * normalize the decimal ascii number 219 * to range .[5-9][0-9]* e0 220 */ 221 bp = 0; /* binary exponent */ 222 while(dp > 0) 223 divascii(a, &na, &dp, &bp); 224 while(dp < 0 || a[0] < '5') 225 mulascii(a, &na, &dp, &bp); 226 227 /* close approx by naive conversion */ 228 mid[0] = 0; 229 mid[1] = 1; 230 for(i=0; (c=a[i]) != '\0'; i++) { 231 mid[0] = mid[0]*10 + (c-'0'); 232 mid[1] = mid[1]*10; 233 if(i >= 8) 234 break; 235 } 236 low[0] = umuldiv(mid[0], One, mid[1]); 237 hig[0] = umuldiv(mid[0]+1, One, mid[1]); 238 for(i=1; i<Prec; i++) { 239 low[i] = 0; 240 hig[i] = One-1; 241 } 242 243 /* binary search for closest mantissa */ 244 for(;;) { 245 /* mid = (hig + low) / 2 */ 246 c = 0; 247 for(i=0; i<Prec; i++) { 248 mid[i] = hig[i] + low[i]; 249 if(c) 250 mid[i] += One; 251 c = mid[i] & 1; 252 mid[i] >>= 1; 253 } 254 frnorm(mid); 255 256 /* compare */ 257 c = fpcmp(a, mid); 258 if(c > 0) { 259 c = 1; 260 for(i=0; i<Prec; i++) 261 if(low[i] != mid[i]) { 262 c = 0; 263 low[i] = mid[i]; 264 } 265 if(c) 266 break; /* between mid and hig */ 267 continue; 268 } 269 if(c < 0) { 270 for(i=0; i<Prec; i++) 271 hig[i] = mid[i]; 272 continue; 273 } 274 275 /* only hard part is if even/odd roundings wants to go up */ 276 c = mid[Prec-1] & (Sigbit-1); 277 if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0) 278 mid[Prec-1] -= c; 279 break; /* exactly mid */ 280 } 281 282 /* normal rounding applies */ 283 c = mid[Prec-1] & (Sigbit-1); 284 mid[Prec-1] -= c; 285 if(c >= Sigbit/2) { 286 mid[Prec-1] += Sigbit; 287 frnorm(mid); 288 } 289 goto out; 290 291 ret0: 292 return 0; 293 294 retnan: 295 return __NaN(); 296 297 retinf: 298 /* 299 * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */ 300 errno = ERANGE; 301 if(flag & Fsign) 302 return -HUGE_VAL; 303 return HUGE_VAL; 304 305 out: 306 d = 0; 307 for(i=0; i<Prec; i++) 308 d = d*One + mid[i]; 309 if(flag & Fsign) 310 d = -d; 311 d = ldexp(d, bp - Prec*Nbits); 312 if(d == 0){ /* underflow */ 313 errno = ERANGE; 314 } 315 return d; 316 } 317 318 static void 319 frnorm(ulong *f) 320 { 321 int i, c; 322 323 c = 0; 324 for(i=Prec-1; i>0; i--) { 325 f[i] += c; 326 c = f[i] >> Nbits; 327 f[i] &= One-1; 328 } 329 f[0] += c; 330 } 331 332 static int 333 fpcmp(char *a, ulong* f) 334 { 335 ulong tf[Prec]; 336 int i, d, c; 337 338 for(i=0; i<Prec; i++) 339 tf[i] = f[i]; 340 341 for(;;) { 342 /* tf *= 10 */ 343 for(i=0; i<Prec; i++) 344 tf[i] = tf[i]*10; 345 frnorm(tf); 346 d = (tf[0] >> Nbits) + '0'; 347 tf[0] &= One-1; 348 349 /* compare next digit */ 350 c = *a; 351 if(c == 0) { 352 if('0' < d) 353 return -1; 354 if(tf[0] != 0) 355 goto cont; 356 for(i=1; i<Prec; i++) 357 if(tf[i] != 0) 358 goto cont; 359 return 0; 360 } 361 if(c > d) 362 return +1; 363 if(c < d) 364 return -1; 365 a++; 366 cont:; 367 } 368 } 369 370 static void 371 divby(char *a, int *na, int b) 372 { 373 int n, c; 374 char *p; 375 376 p = a; 377 n = 0; 378 while(n>>b == 0) { 379 c = *a++; 380 if(c == 0) { 381 while(n) { 382 c = n*10; 383 if(c>>b) 384 break; 385 n = c; 386 } 387 goto xx; 388 } 389 n = n*10 + c-'0'; 390 (*na)--; 391 } 392 for(;;) { 393 c = n>>b; 394 n -= c<<b; 395 *p++ = c + '0'; 396 c = *a++; 397 if(c == 0) 398 break; 399 n = n*10 + c-'0'; 400 } 401 (*na)++; 402 xx: 403 while(n) { 404 n = n*10; 405 c = n>>b; 406 n -= c<<b; 407 *p++ = c + '0'; 408 (*na)++; 409 } 410 *p = 0; 411 } 412 413 static Tab tab1[] = 414 { 415 1, 0, "", 416 3, 1, "7", 417 6, 2, "63", 418 9, 3, "511", 419 13, 4, "8191", 420 16, 5, "65535", 421 19, 6, "524287", 422 23, 7, "8388607", 423 26, 8, "67108863", 424 27, 9, "134217727", 425 }; 426 427 static void 428 divascii(char *a, int *na, int *dp, int *bp) 429 { 430 int b, d; 431 Tab *t; 432 433 d = *dp; 434 if(d >= (int)(nelem(tab1))) 435 d = (int)(nelem(tab1))-1; 436 t = tab1 + d; 437 b = t->bp; 438 if(memcmp(a, t->cmp, t->siz) > 0) 439 d--; 440 *dp -= d; 441 *bp += b; 442 divby(a, na, b); 443 } 444 445 static void 446 mulby(char *a, char *p, char *q, int b) 447 { 448 int n, c; 449 450 n = 0; 451 *p = 0; 452 for(;;) { 453 q--; 454 if(q < a) 455 break; 456 c = *q - '0'; 457 c = (c<<b) + n; 458 n = c/10; 459 c -= n*10; 460 p--; 461 *p = c + '0'; 462 } 463 while(n) { 464 c = n; 465 n = c/10; 466 c -= n*10; 467 p--; 468 *p = c + '0'; 469 } 470 } 471 472 static Tab tab2[] = 473 { 474 1, 1, "", /* dp = 0-0 */ 475 3, 3, "125", 476 6, 5, "15625", 477 9, 7, "1953125", 478 13, 10, "1220703125", 479 16, 12, "152587890625", 480 19, 14, "19073486328125", 481 23, 17, "11920928955078125", 482 26, 19, "1490116119384765625", 483 27, 19, "7450580596923828125", /* dp 8-9 */ 484 }; 485 486 static void 487 mulascii(char *a, int *na, int *dp, int *bp) 488 { 489 char *p; 490 int d, b; 491 Tab *t; 492 493 d = -*dp; 494 if(d >= (int)(nelem(tab2))) 495 d = (int)(nelem(tab2))-1; 496 t = tab2 + d; 497 b = t->bp; 498 if(memcmp(a, t->cmp, t->siz) < 0) 499 d--; 500 p = a + *na; 501 *bp -= b; 502 *dp += d; 503 *na += d; 504 mulby(a, p+d, p, b); 505 } 506 507 static int 508 xcmp(char *a, char *b) 509 { 510 int c1, c2; 511 512 while((c1 = *b++) != '\0') { 513 c2 = *a++; 514 if(isupper(c2)) 515 c2 = tolower(c2); 516 if(c1 != c2) 517 return 1; 518 } 519 return 0; 520 }