mirror of
https://github.com/golang/go
synced 2024-10-05 15:51:22 -06:00
f59cb49a5a
more complex -- constants, variables and print. R=rsc CC=golang-dev https://golang.org/cl/217061
281 lines
3.9 KiB
C
281 lines
3.9 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 "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;
|
|
|
|
s = sigfig(a);
|
|
if(s == 0) {
|
|
// zero
|
|
a->exp = 0;
|
|
a->val.neg = 0;
|
|
return;
|
|
}
|
|
s = (Mpnorm-s) * Mpscale;
|
|
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 - 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;
|
|
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) are
|
|
// IEEE specific. this should be done machine
|
|
// independently or in the 6g half of the compiler
|
|
|
|
// pick up the mantissa in a uvlong
|
|
s = 53;
|
|
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));
|
|
|
|
//print("vm=%.16llux v=%.16llux\n", vm, v);
|
|
// round toward even
|
|
if(v != (1ULL<<63) || (vm&1ULL) != 0)
|
|
vm += v>>63;
|
|
|
|
f = (double)(vm);
|
|
f = ldexp(f, Mpnorm*Mpscale + a->exp - 53);
|
|
|
|
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;
|
|
}
|