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