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 ANY
11 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
24 #define nelem(x) (sizeof(x)/sizeof *(x))
26 #define nil ((void*)0)
27 #define ulong _fmtulong
28 typedef unsigned long ulong;
31 * This routine will convert to arbitrary precision
32 * floating point entirely in multi-precision fixed.
33 * The answer is the closest floating point number to
34 * the given decimal number. Exactly half way are
35 * rounded ala ieee rules.
36 * Method is to scale input decimal between .500 and .999...
37 * with external power of 2, then binary search for the
38 * closest mantissa to this decimal number.
39 * Nmant is is the required precision. (53 for ieee dp)
40 * Nbits is the max number of bits/word. (must be <= 28)
41 * Prec is calculated - the number of words of fixed mantissa.
45 Nbits = 28, /* bits safely represented in a ulong */
46 Nmant = 53, /* bits of precision required */
48 Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
49 Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
51 One = (ulong)(1<<Nbits),
52 Half = (ulong)(One>>1),
55 S0 = 0, /* _ _S0 +S1 #S2 .S3 */
57 S2, /* _+# #S2 .S4 eS5 */
59 S4, /* _+#.# #S4 eS5 */
60 S5, /* _+#.#e +S6 #S7 */
62 S7, /* _+#.#e+# #S7 */
64 Fsign = 1<<0, /* found - */
65 Fesign = 1<<1, /* found e- */
66 Fdpoint = 1<<2, /* found . */
69 static int xcmp(char*, char*);
70 static int fpcmp(char*, ulong*);
71 static void frnorm(ulong*);
72 static void divascii(char*, int*, int*, int*);
73 static void mulascii(char*, int*, int*, int*);
74 static void divby(char*, int*, int);
75 static ulong umuldiv(ulong, ulong, ulong);
77 typedef struct Tab Tab;
86 fmtstrtod(const char *as, char **aas)
88 int na, ona, ex, dp, bp, c, i, flag, state;
89 ulong low[Prec], hig[Prec], mid[Prec], num, den;
93 flag = 0; /* Fsign, Fesign, Fdpoint */
94 na = 0; /* number of digits of a[] */
95 dp = 0; /* na of decimal point */
99 for(s=(char*)as;; s++) {
101 if(c >= '0' && c <= '9') {
117 ex = ex*10 + (c-'0');
120 if(na == 0 && c == '0') {
155 if(state == S0 || state == S1) {
166 if(state == S2 || state == S4) {
176 * clean up return char-pointer
180 if(xcmp(s, "nan") == 0) {
186 if(xcmp(s, "infinity") == 0) {
191 if(xcmp(s, "inf") == 0) {
199 goto ret0; /* no digits found */
201 s--; /* back over +- */
203 s--; /* back over e */
210 while(na > 0 && a[na-1] == '0')
213 goto ret0; /* zero */
215 if(!(flag & Fdpoint))
220 if(dp < -Maxe-Nmant/3){ /* actually -Nmant*log(2)/log(10), but Nmant/3 close enough */
222 goto ret0; /* underflow by exp */
225 goto retinf; /* overflow by exp */
228 * normalize the decimal ascii number
229 * to range .[5-9][0-9]* e0
231 bp = 0; /* binary exponent */
233 divascii(a, &na, &dp, &bp);
234 while(dp < 0 || a[0] < '5')
235 mulascii(a, &na, &dp, &bp);
239 * very small numbers are represented using
240 * bp = -Bias+1. adjust accordingly.
244 divby(a, &na, -bp-Bias+1);
246 memmove(a+ona-na, a, na);
247 memset(a, '0', ona-na);
254 /* close approx by naive conversion */
257 for(i=0; i<9 && (c=a[i]); i++) {
258 num = num*10 + (c-'0');
261 low[0] = umuldiv(num, One, den);
262 hig[0] = umuldiv(num+1, One, den);
263 for(i=1; i<Prec; i++) {
268 /* binary search for closest mantissa */
270 /* mid = (hig + low) / 2 */
272 for(i=0; i<Prec; i++) {
273 mid[i] = hig[i] + low[i];
285 for(i=0; i<Prec; i++)
286 if(low[i] != mid[i]) {
291 break; /* between mid and hig */
295 for(i=0; i<Prec; i++)
300 /* only hard part is if even/odd roundings wants to go up */
301 c = mid[Prec-1] & (Sigbit-1);
302 if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
304 break; /* exactly mid */
307 /* normal rounding applies */
308 c = mid[Prec-1] & (Sigbit-1);
311 mid[Prec-1] += Sigbit;
324 * Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
332 for(i=0; i<Prec; i++)
336 d = ldexp(d, bp - Prec*Nbits);
337 if(d == 0){ /* underflow */
349 for(i=Prec-1; i>0; i--) {
358 fpcmp(char *a, ulong* f)
363 for(i=0; i<Prec; i++)
368 for(i=0; i<Prec; i++)
371 d = (tf[0] >> Nbits) + '0';
374 /* compare next digit */
381 for(i=1; i<Prec; i++)
396 _divby(char *a, int *na, int b)
439 divby(char *a, int *na, int b)
465 divascii(char *a, int *na, int *dp, int *bp)
471 if(d >= (int)(nelem(tab1)))
472 d = (int)(nelem(tab1))-1;
475 if(memcmp(a, t->cmp, t->siz) > 0)
483 mulby(char *a, char *p, char *q, int b)
511 1, 1, "", /* dp = 0-0 */
515 13, 10, "1220703125",
516 16, 12, "152587890625",
517 19, 14, "19073486328125",
518 23, 17, "11920928955078125",
519 26, 19, "1490116119384765625",
520 27, 19, "7450580596923828125", /* dp 8-9 */
524 mulascii(char *a, int *na, int *dp, int *bp)
531 if(d >= (int)(nelem(tab2)))
532 d = (int)(nelem(tab2))-1;
535 if(memcmp(a, t->cmp, t->siz) < 0)
545 xcmp(char *a, char *b)
560 umuldiv(ulong a, ulong b, ulong c)
562 return ((uvlong)a * (uvlong)b) / c;