diff options
Diffstat (limited to 'src/old/c/mpatof.c')
-rw-r--r-- | src/old/c/mpatof.c | 342 |
1 files changed, 0 insertions, 342 deletions
diff --git a/src/old/c/mpatof.c b/src/old/c/mpatof.c deleted file mode 100644 index 07bcf4a27..000000000 --- a/src/old/c/mpatof.c +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include <u.h> -#include <libc.h> - -int mpatof(char*, double*); -int mpatov(char *s, vlong *v); - -enum -{ - Mpscale = 29, /* safely smaller than bits in a long */ - Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */ - Mpbase = 1L<<Mpscale, -}; - -typedef -struct -{ - long a[Mpprec]; - char ovf; -} Mp; - -static void mpint(Mp*, int); -static void mppow(Mp*, int, int); -static void mpmul(Mp*, int); -static void mpadd(Mp*, Mp*); -static int mptof(Mp*, double*); - -/* - * convert a string, s, to floating in *d - * return conversion overflow. - * required syntax is [+-]d*[.]d*[e[+-]d*] - */ -int -mpatof(char *s, double *d) -{ - Mp a, b; - int dp, c, f, ef, ex, zer; - double d1, d2; - - dp = 0; /* digits after decimal point */ - f = 0; /* sign */ - ex = 0; /* exponent */ - zer = 1; /* zero */ - memset(&a, 0, sizeof(a)); - for(;;) { - switch(c = *s++) { - default: - goto bad; - case '-': - f = 1; - case ' ': - case '\t': - case '+': - continue; - case '.': - dp = 1; - continue; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - zer = 0; - case '0': - mpint(&b, c-'0'); - mpmul(&a, 10); - mpadd(&a, &b); - if(dp) - dp++; - continue; - case 'E': - case 'e': - ex = 0; - ef = 0; - for(;;) { - c = *s++; - if(c == '+' || c == ' ' || c == '\t') - continue; - if(c == '-') { - ef = 1; - continue; - } - if(c >= '0' && c <= '9') { - ex = ex*10 + (c-'0'); - continue; - } - break; - } - if(ef) - ex = -ex; - case 0: - break; - } - break; - } - if(a.ovf) - goto bad; - if(zer) { - *d = 0; - return 0; - } - if(dp) - dp--; - dp -= ex; - if(dp > 0) { - /* - * must divide by 10**dp - */ - if(mptof(&a, &d1)) - goto bad; - - /* - * trial exponent of 8**dp - * 8 (being between 5 and 10) - * should pick up all underflows - * in the division of 5**dp. - */ - d2 = frexp(d1, &ex); - d2 = ldexp(d2, ex-3*dp); - if(d2 == 0) - goto bad; - - /* - * decompose each 10 into 5*2. - * create 5**dp in fixed point - * and then play with the exponent - * for the remaining 2**dp. - * note that 5**dp will overflow - * with as few as 134 input digits. - */ - mpint(&a, 1); - mppow(&a, 5, dp); - if(mptof(&a, &d2)) - goto bad; - d1 = frexp(d1/d2, &ex); - d1 = ldexp(d1, ex-dp); - if(d1 == 0) - goto bad; - } else { - /* - * must multiply by 10**|dp| -- - * just do it in fixed point. - */ - mppow(&a, 10, -dp); - if(mptof(&a, &d1)) - goto bad; - } - if(f) - d1 = -d1; - *d = d1; - return 0; - -bad: - return 1; -} - -/* - * convert a to floating in *d - * return conversion overflow - */ -static int -mptof(Mp *a, double *d) -{ - double f, g; - long x, *a1; - int i; - - if(a->ovf) - return 1; - a1 = a->a; - f = ldexp(*a1++, 0); - for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale) - if(x = *a1++) { - g = ldexp(x, i); - /* - * NOTE: the test (g==0) is plan9 - * specific. ansi compliant overflow - * is signaled by HUGE and errno==ERANGE. - * change this for your particular ldexp. - */ - if(g == 0) - return 1; - f += g; /* this could bomb! */ - } - *d = f; - return 0; -} - -/* - * return a += b - */ -static void -mpadd(Mp *a, Mp *b) -{ - int i, c; - long x, *a1, *b1; - - if(b->ovf) - a->ovf = 1; - if(a->ovf) - return; - c = 0; - a1 = a->a; - b1 = b->a; - for(i=0; i<Mpprec; i++) { - x = *a1 + *b1++ + c; - c = 0; - if(x >= Mpbase) { - x -= Mpbase; - c = 1; - } - *a1++ = x; - } - a->ovf = c; -} - -/* - * return a = c - */ -static void -mpint(Mp *a, int c) -{ - - memset(a, 0, sizeof(*a)); - a->a[0] = c; -} - -/* - * return a *= c - */ -static void -mpmul(Mp *a, int c) -{ - Mp p; - int b; - memmove(&p, a, sizeof(p)); - if(!(c & 1)) - memset(a, 0, sizeof(*a)); - c &= ~1; - for(b=2; c; b<<=1) { - mpadd(&p, &p); - if(c & b) { - mpadd(a, &p); - c &= ~b; - } - } -} - -/* - * return a *= b**e - */ -static void -mppow(Mp *a, int b, int e) -{ - int b1; - - b1 = b*b; - b1 = b1*b1; - while(e >= 4) { - mpmul(a, b1); - e -= 4; - if(a->ovf) - return; - } - while(e > 0) { - mpmul(a, b); - e--; - } -} - -/* - * convert a string, s, to vlong in *v - * return conversion overflow. - * required syntax is [0[x]]d* - */ -int -mpatov(char *s, vlong *v) -{ - vlong n, nn; - int c; - n = 0; - c = *s; - if(c == '0') - goto oct; - while(c = *s++) { - if(c >= '0' && c <= '9') - nn = n*10 + c-'0'; - else - goto bad; - if(n < 0 && nn >= 0) - goto bad; - n = nn; - } - goto out; -oct: - s++; - c = *s; - if(c == 'x' || c == 'X') - goto hex; - while(c = *s++) { - if(c >= '0' || c <= '7') - nn = n*8 + c-'0'; - else - goto bad; - if(n < 0 && nn >= 0) - goto bad; - n = nn; - } - goto out; -hex: - s++; - while(c = *s++) { - if(c >= '0' && c <= '9') - c += 0-'0'; - else - if(c >= 'a' && c <= 'f') - c += 10-'a'; - else - if(c >= 'A' && c <= 'F') - c += 10-'A'; - else - goto bad; - nn = n*16 + c; - if(n < 0 && nn >= 0) - goto bad; - n = nn; - } -out: - *v = n; - return 0; - -bad: - *v = ~0; - return 1; -} |