github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/lib9/fmt/strtod.c (about) 1 /* 2 * The authors of this software are Rob Pike and Ken Thompson, 3 * with contributions from Mike Burrows and Sean Dorward. 4 * 5 * Copyright (c) 2002-2006 by Lucent Technologies. 6 * Portions Copyright (c) 2004 Google Inc. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose without fee is hereby granted, provided that this entire notice 10 * is included in all copies of any software which is or includes a copy 11 * or modification of this software and in all copies of the supporting 12 * documentation for such software. 13 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 14 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES 15 * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 16 * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 17 */ 18 19 #include <u.h> 20 #include <errno.h> 21 #include <libc.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++] = (char)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 + (ulong)(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] -= (ulong)c; 291 break; /* exactly mid */ 292 } 293 294 /* normal rounding applies */ 295 c = mid[Prec-1] & (Sigbit-1); 296 mid[Prec-1] -= (ulong)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 + (double)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; 334 ulong c; 335 336 c = 0; 337 for(i=Prec-1; i>0; i--) { 338 f[i] += c; 339 c = f[i] >> Nbits; 340 f[i] &= One-1; 341 } 342 f[0] += c; 343 } 344 345 static int 346 fpcmp(char *a, ulong* f) 347 { 348 ulong tf[Prec]; 349 int i, d, c; 350 351 for(i=0; i<Prec; i++) 352 tf[i] = f[i]; 353 354 for(;;) { 355 /* tf *= 10 */ 356 for(i=0; i<Prec; i++) 357 tf[i] = tf[i]*10; 358 frnorm(tf); 359 d = (int)(tf[0] >> Nbits) + '0'; 360 tf[0] &= One-1; 361 362 /* compare next digit */ 363 c = *a; 364 if(c == 0) { 365 if('0' < d) 366 return -1; 367 if(tf[0] != 0) 368 goto cont; 369 for(i=1; i<Prec; i++) 370 if(tf[i] != 0) 371 goto cont; 372 return 0; 373 } 374 if(c > d) 375 return +1; 376 if(c < d) 377 return -1; 378 a++; 379 cont:; 380 } 381 } 382 383 static void 384 divby(char *a, int *na, int b) 385 { 386 int n, c; 387 char *p; 388 389 p = a; 390 n = 0; 391 while(n>>b == 0) { 392 c = *a++; 393 if(c == 0) { 394 while(n) { 395 c = n*10; 396 if(c>>b) 397 break; 398 n = c; 399 } 400 goto xx; 401 } 402 n = n*10 + c-'0'; 403 (*na)--; 404 } 405 for(;;) { 406 c = n>>b; 407 n -= c<<b; 408 *p++ = (char)(c + '0'); 409 c = *a++; 410 if(c == 0) 411 break; 412 n = n*10 + c-'0'; 413 } 414 (*na)++; 415 xx: 416 while(n) { 417 n = n*10; 418 c = n>>b; 419 n -= c<<b; 420 *p++ = (char)(c + '0'); 421 (*na)++; 422 } 423 *p = 0; 424 } 425 426 static Tab tab1[] = 427 { 428 1, 0, "", 429 3, 1, "7", 430 6, 2, "63", 431 9, 3, "511", 432 13, 4, "8191", 433 16, 5, "65535", 434 19, 6, "524287", 435 23, 7, "8388607", 436 26, 8, "67108863", 437 27, 9, "134217727", 438 }; 439 440 static void 441 divascii(char *a, int *na, int *dp, int *bp) 442 { 443 int b, d; 444 Tab *t; 445 446 d = *dp; 447 if(d >= (int)(nelem(tab1))) 448 d = (int)(nelem(tab1))-1; 449 t = tab1 + d; 450 b = t->bp; 451 if(memcmp(a, t->cmp, (size_t)t->siz) > 0) 452 d--; 453 *dp -= d; 454 *bp += b; 455 divby(a, na, b); 456 } 457 458 static void 459 mulby(char *a, char *p, char *q, int b) 460 { 461 int n, c; 462 463 n = 0; 464 *p = 0; 465 for(;;) { 466 q--; 467 if(q < a) 468 break; 469 c = *q - '0'; 470 c = (c<<b) + n; 471 n = c/10; 472 c -= n*10; 473 p--; 474 *p = (char)(c + '0'); 475 } 476 while(n) { 477 c = n; 478 n = c/10; 479 c -= n*10; 480 p--; 481 *p = (char)(c + '0'); 482 } 483 } 484 485 static Tab tab2[] = 486 { 487 1, 1, "", /* dp = 0-0 */ 488 3, 3, "125", 489 6, 5, "15625", 490 9, 7, "1953125", 491 13, 10, "1220703125", 492 16, 12, "152587890625", 493 19, 14, "19073486328125", 494 23, 17, "11920928955078125", 495 26, 19, "1490116119384765625", 496 27, 19, "7450580596923828125", /* dp 8-9 */ 497 }; 498 499 static void 500 mulascii(char *a, int *na, int *dp, int *bp) 501 { 502 char *p; 503 int d, b; 504 Tab *t; 505 506 d = -*dp; 507 if(d >= (int)(nelem(tab2))) 508 d = (int)(nelem(tab2))-1; 509 t = tab2 + d; 510 b = t->bp; 511 if(memcmp(a, t->cmp, (size_t)t->siz) < 0) 512 d--; 513 p = a + *na; 514 *bp -= b; 515 *dp += d; 516 *na += d; 517 mulby(a, p+d, p, b); 518 } 519 520 static int 521 xcmp(char *a, char *b) 522 { 523 int c1, c2; 524 525 while((c1 = *b++) != '\0') { 526 c2 = *a++; 527 if(isupper(c2)) 528 c2 = tolower(c2); 529 if(c1 != c2) 530 return 1; 531 } 532 return 0; 533 }