diff options
author | Russ Cox <rsc@golang.org> | 2008-11-20 10:54:02 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2008-11-20 10:54:02 -0800 |
commit | e568a3dc2af6a801621c5b826969ba5a2b17f05f (patch) | |
tree | d3406f3a7660f54f9349fb10c2432445311cd0a4 /src/lib/math/pow.go | |
parent | 9c1f310153d68e56eb53ca1313406562db622b94 (diff) | |
download | golang-e568a3dc2af6a801621c5b826969ba5a2b17f05f.tar.gz |
more accurate Log, Exp, Pow.
move test.go to alll_test.go.
R=r
DELTA=1024 (521 added, 425 deleted, 78 changed)
OCL=19687
CL=19695
Diffstat (limited to 'src/lib/math/pow.go')
-rw-r--r-- | src/lib/math/pow.go | 106 |
1 files changed, 66 insertions, 40 deletions
diff --git a/src/lib/math/pow.go b/src/lib/math/pow.go index 9e63db74b..bdecf1329 100644 --- a/src/lib/math/pow.go +++ b/src/lib/math/pow.go @@ -6,56 +6,82 @@ package math import "math" -/* - arg1 ^ arg2 (exponentiation) - */ +// x^y: exponentation +export func Pow(x, y float64) float64 { + // TODO: x or y NaN, ±Inf, maybe ±0. + switch { + case y == 0: + return 1; + case y == 1: + return x; + case x == 0 && y > 0: + return 0; + case x == 0 && y < 0: + return sys.Inf(1); + case y == 0.5: + return Sqrt(x); + case y == -0.5: + return 1 / Sqrt(x); + } -export func Pow(arg1,arg2 float64) float64 { - if arg2 < 0 { - return 1/Pow(arg1, -arg2); + absy := y; + flip := false; + if absy < 0 { + absy = -absy; + flip = true; + } + yi, yf := sys.modf(absy); + if yf != 0 && x < 0 { + return sys.NaN(); + } + if yi >= 1<<63 { + return Exp(y * Log(x)); } - if arg1 <= 0 { - if(arg1 == 0) { - if arg2 <= 0 { - return sys.NaN(); - } - return 0; - } - temp := Floor(arg2); - if temp != arg2 { - panic(sys.NaN()); - } + ans := float64(1); - l := int32(temp); - if l&1 != 0 { - return -Pow(-arg1, arg2); + // ans *= x^yf + if yf != 0 { + if yf > 0.5 { + yf--; + yi++; } - return Pow(-arg1, arg2); + ans = Exp(yf * Log(x)); } - temp := Floor(arg2); - if temp != arg2 { - if arg2-temp == .5 { - if temp == 0 { - return Sqrt(arg1); + // ans *= x^yi + // by multiplying in successive squarings + // of x according to bits of yi. + // accumulate powers of two into exp. + // will still have to do ans *= 2^exp later. + x1, xe := sys.frexp(x); + exp := 0; + if i := int64(yi); i != 0 { + for { + if i&1 == 1 { + ans *= x1; + exp += xe; + } + i >>= 1; + if i == 0 { + break; + } + x1 *= x1; + xe <<= 1; + if x1 < .5 { + x1 += x1; + xe--; } - return Pow(arg1, temp) * Sqrt(arg1); } - return Exp(arg2 * Log(arg1)); } - l := int32(temp); - temp = 1; - for { - if l&1 != 0 { - temp = temp*arg1; - } - l >>= 1; - if l == 0 { - return temp; - } - arg1 *= arg1; + // ans *= 2^exp + // if flip { ans = 1 / ans } + // but in the opposite order + if flip { + ans = 1 / ans; + exp = -exp; } - panic("unreachable") + return sys.ldexp(ans, exp); } + |