mirror of
https://github.com/golang/go
synced 2024-11-20 11:14:45 -07:00
61f84a2cdc
#include "go.h" (or "gg.h") becomes #include <u.h> #include <libc.h> #include "go.h" so that go.y can #include <stdio.h> after <u.h> but before "go.h". This is necessary on Plan 9. R=ken2 CC=golang-dev https://golang.org/cl/4971041
316 lines
4.5 KiB
C
316 lines
4.5 KiB
C
// 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>
|
|
#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;
|
|
}
|