summaryrefslogtreecommitdiff
path: root/src/cmd/gc/mparith3.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/cmd/gc/mparith3.c
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-5ff4c17907d5b19510a62e08fd8d3b11e62b431d.tar.gz
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/cmd/gc/mparith3.c')
-rw-r--r--src/cmd/gc/mparith3.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
new file mode 100644
index 000000000..b11a4f5f1
--- /dev/null
+++ b/src/cmd/gc/mparith3.c
@@ -0,0 +1,313 @@
+// 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"
+
+/*
+ * returns the leading non-zero
+ * word of the number
+ */
+int
+sigfig(Mpflt *a)
+{
+ int i;
+
+ for(i=Mpprec-1; i>=0; i--)
+ if(a->val.a[i] != 0)
+ break;
+//print("sigfig %d %d\n", i-z+1, z);
+ return i+1;
+}
+
+/*
+ * shifts the leading non-zero
+ * word of the number to Mpnorm
+ */
+void
+mpnorm(Mpflt *a)
+{
+ int s, os;
+ long x;
+
+ os = sigfig(a);
+ if(os == 0) {
+ // zero
+ a->exp = 0;
+ a->val.neg = 0;
+ return;
+ }
+
+ // this will normalize to the nearest word
+ x = a->val.a[os-1];
+ s = (Mpnorm-os) * Mpscale;
+
+ // further normalize to the nearest bit
+ for(;;) {
+ x <<= 1;
+ if(x & Mpbase)
+ break;
+ s++;
+ if(x == 0) {
+ // this error comes from trying to
+ // convert an Inf or something
+ // where the initial x=0x80000000
+ s = (Mpnorm-os) * Mpscale;
+ break;
+ }
+ }
+
+ mpshiftfix(&a->val, s);
+ a->exp -= s;
+}
+
+/// implements float arihmetic
+
+void
+mpaddfltflt(Mpflt *a, Mpflt *b)
+{
+ int sa, sb, s;
+ Mpflt c;
+
+ if(Mpdebug)
+ print("\n%F + %F", a, b);
+
+ sa = sigfig(a);
+ if(sa == 0) {
+ mpmovefltflt(a, b);
+ goto out;
+ }
+
+ sb = sigfig(b);
+ if(sb == 0)
+ goto out;
+
+ s = a->exp - b->exp;
+ if(s > 0) {
+ // a is larger, shift b right
+ mpmovefltflt(&c, b);
+ mpshiftfix(&c.val, -s);
+ mpaddfixfix(&a->val, &c.val);
+ goto out;
+ }
+ if(s < 0) {
+ // b is larger, shift a right
+ mpshiftfix(&a->val, s);
+ a->exp -= s;
+ mpaddfixfix(&a->val, &b->val);
+ goto out;
+ }
+ mpaddfixfix(&a->val, &b->val);
+
+out:
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n\n", a);
+}
+
+void
+mpmulfltflt(Mpflt *a, Mpflt *b)
+{
+ int sa, sb;
+
+ if(Mpdebug)
+ print("%F\n * %F\n", a, b);
+
+ sa = sigfig(a);
+ if(sa == 0) {
+ // zero
+ a->exp = 0;
+ a->val.neg = 0;
+ return;
+ }
+
+ sb = sigfig(b);
+ if(sb == 0) {
+ // zero
+ mpmovefltflt(a, b);
+ return;
+ }
+
+ mpmulfract(&a->val, &b->val);
+ a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
+
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n\n", a);
+}
+
+void
+mpdivfltflt(Mpflt *a, Mpflt *b)
+{
+ int sa, sb;
+ Mpflt c;
+
+ if(Mpdebug)
+ print("%F\n / %F\n", a, b);
+
+ sb = sigfig(b);
+ if(sb == 0) {
+ // zero and ovfl
+ a->exp = 0;
+ a->val.neg = 0;
+ a->val.ovf = 1;
+ yyerror("mpdivfltflt divide by zero");
+ return;
+ }
+
+ sa = sigfig(a);
+ if(sa == 0) {
+ // zero
+ a->exp = 0;
+ a->val.neg = 0;
+ return;
+ }
+
+ // adjust b to top
+ mpmovefltflt(&c, b);
+ mpshiftfix(&c.val, Mpscale);
+
+ // divide
+ mpdivfract(&a->val, &c.val);
+ a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
+
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n\n", a);
+}
+
+double
+mpgetflt(Mpflt *a)
+{
+ int s, i, e;
+ uvlong v, vm;
+ double f;
+
+ if(a->val.ovf)
+ yyerror("mpgetflt ovf");
+
+ s = sigfig(a);
+ if(s == 0)
+ return 0;
+
+ if(s != Mpnorm) {
+ yyerror("mpgetflt norm");
+ mpnorm(a);
+ }
+
+ while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
+ mpshiftfix(&a->val, 1);
+ a->exp -= 1;
+ }
+
+ // the magic numbers (64, 63, 53, 10, -1074) are
+ // IEEE specific. this should be done machine
+ // independently or in the 6g half of the compiler
+
+ // pick up the mantissa and a rounding bit in a uvlong
+ s = 53+1;
+ v = 0;
+ for(i=Mpnorm-1; s>=Mpscale; i--) {
+ v = (v<<Mpscale) | a->val.a[i];
+ s -= Mpscale;
+ }
+ vm = v;
+ if(s > 0)
+ vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
+
+ // continue with 64 more bits
+ s += 64;
+ for(; s>=Mpscale; i--) {
+ v = (v<<Mpscale) | a->val.a[i];
+ s -= Mpscale;
+ }
+ if(s > 0)
+ v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
+
+ // gradual underflow
+ e = Mpnorm*Mpscale + a->exp - 53;
+ if(e < -1074) {
+ s = -e - 1074;
+ if(s > 54)
+ s = 54;
+ v |= vm & ((1ULL<<s) - 1);
+ vm >>= s;
+ e = -1074;
+ }
+
+//print("vm=%.16llux v=%.16llux\n", vm, v);
+ // round toward even
+ if(v != 0 || (vm&2ULL) != 0)
+ vm = (vm>>1) + (vm&1ULL);
+ else
+ vm >>= 1;
+
+ f = (double)(vm);
+ f = ldexp(f, e);
+
+ if(a->val.neg)
+ f = -f;
+ return f;
+}
+
+void
+mpmovecflt(Mpflt *a, double c)
+{
+ int i;
+ double f;
+ long l;
+
+ if(Mpdebug)
+ print("\nconst %g", c);
+ mpmovecfix(&a->val, 0);
+ a->exp = 0;
+ if(c == 0)
+ goto out;
+ if(c < 0) {
+ a->val.neg = 1;
+ c = -c;
+ }
+
+ f = frexp(c, &i);
+ a->exp = i;
+
+ for(i=0; i<10; i++) {
+ f = f*Mpbase;
+ l = floor(f);
+ f = f - l;
+ a->exp -= Mpscale;
+ a->val.a[0] = l;
+ if(f == 0)
+ break;
+ mpshiftfix(&a->val, Mpscale);
+ }
+
+out:
+ mpnorm(a);
+ if(Mpdebug)
+ print(" = %F\n", a);
+}
+
+void
+mpnegflt(Mpflt *a)
+{
+ a->val.neg ^= 1;
+}
+
+int
+mptestflt(Mpflt *a)
+{
+ int s;
+
+ if(Mpdebug)
+ print("\n%F?", a);
+ s = sigfig(a);
+ if(s != 0) {
+ s = +1;
+ if(a->val.neg)
+ s = -1;
+ }
+ if(Mpdebug)
+ print(" = %d\n", s);
+ return s;
+}