summaryrefslogtreecommitdiff
path: root/src/old/c/mpatof.c
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2008-06-04 14:46:07 -0700
committerRob Pike <r@golang.org>2008-06-04 14:46:07 -0700
commit5cf1e37b96825023b2da8de9be3a07d1987bb306 (patch)
treefda9e615c7d6ddb748cee567027fae05ba9215ae /src/old/c/mpatof.c
parent0a2697043d69739b27b6ba872b2092a4c2bb61a8 (diff)
downloadgolang-5cf1e37b96825023b2da8de9be3a07d1987bb306.tar.gz
move old code into 'old' directory
add src/test dir SVN=121166
Diffstat (limited to 'src/old/c/mpatof.c')
-rw-r--r--src/old/c/mpatof.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/src/old/c/mpatof.c b/src/old/c/mpatof.c
new file mode 100644
index 000000000..07bcf4a27
--- /dev/null
+++ b/src/old/c/mpatof.c
@@ -0,0 +1,342 @@
+// 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;
+}