summaryrefslogtreecommitdiff
path: root/src/cmd/gc/mparith1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/mparith1.c')
-rw-r--r--src/cmd/gc/mparith1.c509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
new file mode 100644
index 000000000..6cd4e2500
--- /dev/null
+++ b/src/cmd/gc/mparith1.c
@@ -0,0 +1,509 @@
+// 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 "go.h"
+
+/// uses arithmetic
+
+int
+mpcmpfixflt(Mpint *a, Mpflt *b)
+{
+ char buf[500];
+ Mpflt c;
+
+ snprint(buf, sizeof(buf), "%B", a);
+ mpatoflt(&c, buf);
+ return mpcmpfltflt(&c, b);
+}
+
+int
+mpcmpfltfix(Mpflt *a, Mpint *b)
+{
+ char buf[500];
+ Mpflt c;
+
+ snprint(buf, sizeof(buf), "%B", b);
+ mpatoflt(&c, buf);
+ return mpcmpfltflt(a, &c);
+}
+
+int
+mpcmpfixfix(Mpint *a, Mpint *b)
+{
+ Mpint c;
+
+ mpmovefixfix(&c, a);
+ mpsubfixfix(&c, b);
+ return mptestfix(&c);
+}
+
+int
+mpcmpfixc(Mpint *b, vlong c)
+{
+ Mpint a;
+
+ mpmovecfix(&a, c);
+ return mpcmpfixfix(&a, b);
+}
+
+int
+mpcmpfltflt(Mpflt *a, Mpflt *b)
+{
+ Mpflt c;
+
+ mpmovefltflt(&c, a);
+ mpsubfltflt(&c, b);
+ return mptestflt(&c);
+}
+
+int
+mpcmpfltc(Mpflt *b, double c)
+{
+ Mpflt a;
+
+ mpmovecflt(&a, c);
+ return mpcmpfltflt(&a, b);
+}
+
+void
+mpsubfixfix(Mpint *a, Mpint *b)
+{
+ mpnegfix(a);
+ mpaddfixfix(a, b);
+ mpnegfix(a);
+}
+
+void
+mpsubfltflt(Mpflt *a, Mpflt *b)
+{
+ mpnegflt(a);
+ mpaddfltflt(a, b);
+ mpnegflt(a);
+}
+
+void
+mpaddcfix(Mpint *a, vlong c)
+{
+ Mpint b;
+
+ mpmovecfix(&b, c);
+ mpaddfixfix(a, &b);
+}
+
+void
+mpaddcflt(Mpflt *a, double c)
+{
+ Mpflt b;
+
+ mpmovecflt(&b, c);
+ mpaddfltflt(a, &b);
+}
+
+void
+mpmulcfix(Mpint *a, vlong c)
+{
+ Mpint b;
+
+ mpmovecfix(&b, c);
+ mpmulfixfix(a, &b);
+}
+
+void
+mpmulcflt(Mpflt *a, double c)
+{
+ Mpflt b;
+
+ mpmovecflt(&b, c);
+ mpmulfltflt(a, &b);
+}
+
+void
+mpdivfixfix(Mpint *a, Mpint *b)
+{
+ Mpint q, r;
+
+ mpdivmodfixfix(&q, &r, a, b);
+ mpmovefixfix(a, &q);
+}
+
+void
+mpmodfixfix(Mpint *a, Mpint *b)
+{
+ Mpint q, r;
+
+ mpdivmodfixfix(&q, &r, a, b);
+ mpmovefixfix(a, &r);
+}
+
+void
+mpcomfix(Mpint *a)
+{
+ Mpint b;
+
+ mpmovecfix(&b, 1);
+ mpnegfix(a);
+ mpsubfixfix(a, &b);
+}
+
+void
+mpmovefixflt(Mpflt *a, Mpint *b)
+{
+ a->val = *b;
+ a->exp = 0;
+ mpnorm(a);
+}
+
+// convert (truncate) b to a.
+// return -1 (but still convert) if b was non-integer.
+static int
+mpexactfltfix(Mpint *a, Mpflt *b)
+{
+ Mpflt f;
+
+ *a = b->val;
+ mpshiftfix(a, b->exp);
+ if(b->exp < 0) {
+ f.val = *a;
+ f.exp = 0;
+ mpnorm(&f);
+ if(mpcmpfltflt(b, &f) != 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+mpmovefltfix(Mpint *a, Mpflt *b)
+{
+ Mpflt f;
+ int i;
+
+ if(mpexactfltfix(a, b) == 0)
+ return 0;
+
+ // try rounding down a little
+ f = *b;
+ f.val.a[0] = 0;
+ if(mpexactfltfix(a, &f) == 0)
+ return 0;
+
+ // try rounding up a little
+ for(i=1; i<Mpprec; i++) {
+ f.val.a[i]++;
+ if(f.val.a[i] != Mpbase)
+ break;
+ f.val.a[i] = 0;
+ }
+ mpnorm(&f);
+ if(mpexactfltfix(a, &f) == 0)
+ return 0;
+
+ return -1;
+}
+
+void
+mpmovefixfix(Mpint *a, Mpint *b)
+{
+ *a = *b;
+}
+
+void
+mpmovefltflt(Mpflt *a, Mpflt *b)
+{
+ *a = *b;
+}
+
+static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
+static void
+mppow10flt(Mpflt *a, int p)
+{
+ if(p < 0)
+ abort();
+ if(p < nelem(tab)) {
+ mpmovecflt(a, tab[p]);
+ return;
+ }
+ mppow10flt(a, p>>1);
+ mpmulfltflt(a, a);
+ if(p & 1)
+ mpmulcflt(a, 10);
+}
+
+//
+// floating point input
+// required syntax is [+-]d*[.]d*[e[+-]d*]
+//
+void
+mpatoflt(Mpflt *a, char *as)
+{
+ Mpflt b;
+ int dp, c, f, ef, ex, eb;
+ char *s;
+
+ s = as;
+ dp = 0; /* digits after decimal point */
+ f = 0; /* sign */
+ ex = 0; /* exponent */
+ eb = 0; /* binary point */
+
+ mpmovecflt(a, 0.0);
+ 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':
+ case '0':
+ mpmulcflt(a, 10);
+ mpaddcflt(a, c-'0');
+ if(dp)
+ dp++;
+ continue;
+
+ case 'P':
+ case 'p':
+ eb = 1;
+
+ 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');
+ if(ex > 1e8) {
+ yyerror("exponent out of range");
+ errorexit();
+ }
+ continue;
+ }
+ break;
+ }
+ if(ef)
+ ex = -ex;
+
+ case 0:
+ break;
+ }
+ break;
+ }
+
+ if(eb) {
+ if(dp)
+ goto bad;
+ a->exp += ex;
+ goto out;
+ }
+
+ if(dp)
+ dp--;
+ if(mpcmpfltc(a, 0.0) != 0) {
+ if(ex >= dp) {
+ mppow10flt(&b, ex-dp);
+ mpmulfltflt(a, &b);
+ } else {
+ mppow10flt(&b, dp-ex);
+ mpdivfltflt(a, &b);
+ }
+ }
+
+out:
+ if(f)
+ mpnegflt(a);
+ return;
+
+bad:
+ yyerror("set ovf in mpatof");
+ mpmovecflt(a, 0.0);
+}
+
+//
+// fixed point input
+// required syntax is [+-][0[x]]d*
+//
+void
+mpatofix(Mpint *a, char *as)
+{
+ int c, f;
+ char *s;
+
+ s = as;
+ f = 0;
+ mpmovecfix(a, 0);
+
+ c = *s++;
+ switch(c) {
+ case '-':
+ f = 1;
+
+ case '+':
+ c = *s++;
+ if(c != '0')
+ break;
+
+ case '0':
+ goto oct;
+ }
+
+ while(c) {
+ if(c >= '0' && c <= '9') {
+ mpmulcfix(a, 10);
+ mpaddcfix(a, c-'0');
+ c = *s++;
+ continue;
+ }
+ goto bad;
+ }
+ goto out;
+
+oct:
+ c = *s++;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c) {
+ if(c >= '0' && c <= '7') {
+ mpmulcfix(a, 8);
+ mpaddcfix(a, c-'0');
+ c = *s++;
+ continue;
+ }
+ goto bad;
+ }
+ goto out;
+
+hex:
+ c = *s++;
+ while(c) {
+ if(c >= '0' && c <= '9') {
+ mpmulcfix(a, 16);
+ mpaddcfix(a, c-'0');
+ c = *s++;
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ mpmulcfix(a, 16);
+ mpaddcfix(a, c+10-'a');
+ c = *s++;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ mpmulcfix(a, 16);
+ mpaddcfix(a, c+10-'A');
+ c = *s++;
+ continue;
+ }
+ goto bad;
+ }
+
+out:
+ if(f)
+ mpnegfix(a);
+ return;
+
+bad:
+ yyerror("set ovf in mpatov: %s", as);
+ mpmovecfix(a, 0);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char buf[500], *p;
+ Mpint *xval, q, r, ten;
+ int f;
+
+ xval = va_arg(fp->args, Mpint*);
+ mpmovefixfix(&q, xval);
+ f = 0;
+ if(mptestfix(&q) < 0) {
+ f = 1;
+ mpnegfix(&q);
+ }
+ mpmovecfix(&ten, 10);
+
+ p = &buf[sizeof(buf)];
+ *--p = 0;
+ for(;;) {
+ mpdivmodfixfix(&q, &r, &q, &ten);
+ *--p = mpgetfix(&r) + '0';
+ if(mptestfix(&q) <= 0)
+ break;
+ }
+ if(f)
+ *--p = '-';
+ return fmtstrcpy(fp, p);
+}
+
+int
+Fconv(Fmt *fp)
+{
+ char buf[500];
+ Mpflt *fvp, fv;
+ double d;
+
+ fvp = va_arg(fp->args, Mpflt*);
+ if(fp->flags & FmtSharp) {
+ // alternate form - decimal for error messages.
+ // for well in range, convert to double and use print's %g
+ if(-900 < fvp->exp && fvp->exp < 900) {
+ d = mpgetflt(fvp);
+ if(d >= 0 && (fp->flags & FmtSign))
+ fmtprint(fp, "+");
+ return fmtprint(fp, "%g", d);
+ }
+ // TODO(rsc): for well out of range, print
+ // an approximation like 1.234e1000
+ }
+
+ if(sigfig(fvp) == 0) {
+ snprint(buf, sizeof(buf), "0p+0");
+ goto out;
+ }
+ fv = *fvp;
+
+ while(fv.val.a[0] == 0) {
+ mpshiftfix(&fv.val, -Mpscale);
+ fv.exp += Mpscale;
+ }
+ while((fv.val.a[0]&1) == 0) {
+ mpshiftfix(&fv.val, -1);
+ fv.exp += 1;
+ }
+
+ if(fv.exp >= 0) {
+ snprint(buf, sizeof(buf), "%Bp+%d", &fv.val, fv.exp);
+ goto out;
+ }
+ snprint(buf, sizeof(buf), "%Bp-%d", &fv.val, -fv.exp);
+
+out:
+ return fmtstrcpy(fp, buf);
+}