summaryrefslogtreecommitdiff
path: root/src/pkg/math
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/math')
-rw-r--r--src/pkg/math/all_test.go118
-rw-r--r--src/pkg/math/bits.go10
-rw-r--r--src/pkg/math/frexp.go8
-rw-r--r--src/pkg/math/gamma.go2
-rw-r--r--src/pkg/math/jn.go4
-rw-r--r--src/pkg/math/ldexp.go28
-rw-r--r--src/pkg/math/lgamma.go2
-rw-r--r--src/pkg/math/logb.go15
-rw-r--r--src/pkg/math/pow.go2
9 files changed, 170 insertions, 19 deletions
diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go
index 6033d37e3..d2a7d411e 100644
--- a/src/pkg/math/all_test.go
+++ b/src/pkg/math/all_test.go
@@ -1112,6 +1112,33 @@ var jM3SC = []float64{
NaN(),
}
+var vfldexpSC = []fi{
+ {0, 0},
+ {0, -1075},
+ {0, 1024},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), -1075},
+ {Copysign(0, -1), 1024},
+ {Inf(1), 0},
+ {Inf(1), -1024},
+ {Inf(-1), 0},
+ {Inf(-1), -1024},
+ {NaN(), -1024},
+}
+var ldexpSC = []float64{
+ 0,
+ 0,
+ 0,
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Inf(1),
+ Inf(1),
+ Inf(-1),
+ Inf(-1),
+ NaN(),
+}
+
var vflgammaSC = []float64{
Inf(-1),
-3,
@@ -1440,6 +1467,65 @@ var yM3SC = []float64{
NaN(),
}
+// arguments and expected results for boundary cases
+const (
+ SmallestNormalFloat64 = 2.2250738585072014e-308 // 2**-1022
+ LargestSubnormalFloat64 = SmallestNormalFloat64 - SmallestNonzeroFloat64
+)
+
+var vffrexpBC = []float64{
+ SmallestNormalFloat64,
+ LargestSubnormalFloat64,
+ SmallestNonzeroFloat64,
+ MaxFloat64,
+ -SmallestNormalFloat64,
+ -LargestSubnormalFloat64,
+ -SmallestNonzeroFloat64,
+ -MaxFloat64,
+}
+var frexpBC = []fi{
+ {0.5, -1021},
+ {0.99999999999999978, -1022},
+ {0.5, -1073},
+ {0.99999999999999989, 1024},
+ {-0.5, -1021},
+ {-0.99999999999999978, -1022},
+ {-0.5, -1073},
+ {-0.99999999999999989, 1024},
+}
+
+var vfldexpBC = []fi{
+ {SmallestNormalFloat64, -52},
+ {LargestSubnormalFloat64, -51},
+ {SmallestNonzeroFloat64, 1074},
+ {MaxFloat64, -(1023 + 1074)},
+ {1, -1075},
+ {-1, -1075},
+ {1, 1024},
+ {-1, 1024},
+}
+var ldexpBC = []float64{
+ SmallestNonzeroFloat64,
+ 1e-323, // 2**-1073
+ 1,
+ 1e-323, // 2**-1073
+ 0,
+ Copysign(0, -1),
+ Inf(1),
+ Inf(-1),
+}
+
+var logbBC = []float64{
+ -1022,
+ -1023,
+ -1074,
+ 1023,
+ -1022,
+ -1023,
+ -1074,
+ 1023,
+}
+
func tolerance(a, b, e float64) bool {
d := a - b
if d < 0 {
@@ -1792,6 +1878,11 @@ func TestFrexp(t *testing.T) {
t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i)
}
}
+ for i := 0; i < len(vffrexpBC); i++ {
+ if f, j := Frexp(vffrexpBC[i]); !alike(frexpBC[i].f, f) || frexpBC[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpBC[i], f, j, frexpBC[i].f, frexpBC[i].i)
+ }
+ }
}
func TestGamma(t *testing.T) {
@@ -1833,6 +1924,11 @@ func TestIlogb(t *testing.T) {
t.Errorf("Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i])
}
}
+ for i := 0; i < len(vffrexpBC); i++ {
+ if e := Ilogb(vffrexpBC[i]); int(logbBC[i]) != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vffrexpBC[i], e, int(logbBC[i]))
+ }
+ }
}
func TestJ0(t *testing.T) {
@@ -1891,6 +1987,21 @@ func TestLdexp(t *testing.T) {
t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i])
}
}
+ for i := 0; i < len(vfldexpSC); i++ {
+ if f := Ldexp(vfldexpSC[i].f, vfldexpSC[i].i); !alike(ldexpSC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpSC[i].f, vfldexpSC[i].i, f, ldexpSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if f := Ldexp(frexpBC[i].f, frexpBC[i].i); !alike(vffrexpBC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpBC[i].f, frexpBC[i].i, f, vffrexpBC[i])
+ }
+ }
+ for i := 0; i < len(vfldexpBC); i++ {
+ if f := Ldexp(vfldexpBC[i].f, vfldexpBC[i].i); !alike(ldexpBC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpBC[i].f, vfldexpBC[i].i, f, ldexpBC[i])
+ }
+ }
}
func TestLgamma(t *testing.T) {
@@ -1934,6 +2045,11 @@ func TestLogb(t *testing.T) {
t.Errorf("Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i])
}
}
+ for i := 0; i < len(vffrexpBC); i++ {
+ if e := Logb(vffrexpBC[i]); !alike(logbBC[i], e) {
+ t.Errorf("Ilogb(%g) = %g, want %g", vffrexpBC[i], e, logbBC[i])
+ }
+ }
}
func TestLog10(t *testing.T) {
@@ -1960,7 +2076,7 @@ func TestLog1p(t *testing.T) {
t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i])
}
}
- a := float64(9)
+ a := 9.0
if f := Log1p(a); f != Ln10 {
t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10)
}
diff --git a/src/pkg/math/bits.go b/src/pkg/math/bits.go
index 1a97e7679..a1dca3ed6 100644
--- a/src/pkg/math/bits.go
+++ b/src/pkg/math/bits.go
@@ -47,3 +47,13 @@ func IsInf(f float64, sign int) bool {
// return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf;
return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64
}
+
+// normalize returns a normal number y and exponent exp
+// satisfying x == y × 2**exp. It assumes x is finite and non-zero.
+func normalize(x float64) (y float64, exp int) {
+ const SmallestNormal = 2.2250738585072014e-308 // 2**-1022
+ if Fabs(x) < SmallestNormal {
+ return x * (1 << 52), -52
+ }
+ return x, 0
+}
diff --git a/src/pkg/math/frexp.go b/src/pkg/math/frexp.go
index 203219c0d..867b78f36 100644
--- a/src/pkg/math/frexp.go
+++ b/src/pkg/math/frexp.go
@@ -8,6 +8,11 @@ package math
// and an integral power of two.
// It returns frac and exp satisfying f == frac × 2**exp,
// with the absolute value of frac in the interval [½, 1).
+//
+// Special cases are:
+// Frexp(±0) = ±0, 0
+// Frexp(±Inf) = ±Inf, 0
+// Frexp(NaN) = NaN, 0
func Frexp(f float64) (frac float64, exp int) {
// TODO(rsc): Remove manual inlining of IsNaN, IsInf
// when compiler does it for us
@@ -18,8 +23,9 @@ func Frexp(f float64) (frac float64, exp int) {
case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f):
return f, 0
}
+ f, exp = normalize(f)
x := Float64bits(f)
- exp = int((x>>shift)&mask) - bias + 1
+ exp += int((x>>shift)&mask) - bias + 1
x &^= mask << shift
x |= (-1 + bias) << shift
frac = Float64frombits(x)
diff --git a/src/pkg/math/gamma.go b/src/pkg/math/gamma.go
index 4c5b17d05..73ca0e53a 100644
--- a/src/pkg/math/gamma.go
+++ b/src/pkg/math/gamma.go
@@ -151,7 +151,7 @@ func Gamma(x float64) float64 {
}
// Reduce argument
- z := float64(1)
+ z := 1.0
for x >= 3 {
x = x - 1
z = z * x
diff --git a/src/pkg/math/jn.go b/src/pkg/math/jn.go
index 7d3174310..9024af3c2 100644
--- a/src/pkg/math/jn.go
+++ b/src/pkg/math/jn.go
@@ -132,7 +132,7 @@ func Jn(n int, x float64) float64 {
} else {
temp := x * 0.5
b = temp
- a := float64(1)
+ a := 1.0
for i := 2; i <= n; i++ {
a *= float64(i) // a = n!
b *= temp // b = (x/2)**n
@@ -181,7 +181,7 @@ func Jn(n int, x float64) float64 {
q0, q1 = q1, z*q1-q0
}
m := n + n
- t := float64(0)
+ t := 0.0
for i := 2 * (n + k); i >= m; i -= 2 {
t = 1 / (float64(i)/x - t)
}
diff --git a/src/pkg/math/ldexp.go b/src/pkg/math/ldexp.go
index d04bf1581..96c95cad4 100644
--- a/src/pkg/math/ldexp.go
+++ b/src/pkg/math/ldexp.go
@@ -6,6 +6,11 @@ package math
// Ldexp is the inverse of Frexp.
// It returns frac × 2**exp.
+//
+// Special cases are:
+// Ldexp(±0, exp) = ±0
+// Ldexp(±Inf, exp) = ±Inf
+// Ldexp(NaN, exp) = NaN
func Ldexp(frac float64, exp int) float64 {
// TODO(rsc): Remove manual inlining of IsNaN, IsInf
// when compiler does it for us
@@ -13,21 +18,28 @@ func Ldexp(frac float64, exp int) float64 {
switch {
case frac == 0:
return frac // correctly return -0
- case frac != frac: // IsNaN(frac):
- return NaN()
+ case frac < -MaxFloat64 || frac > MaxFloat64 || frac != frac: // IsInf(frac, 0) || IsNaN(frac):
+ return frac
}
+ frac, e := normalize(frac)
+ exp += e
x := Float64bits(frac)
- exp += int(x>>shift) & mask
- if exp <= 0 {
- return 0 // underflow
+ exp += int(x>>shift)&mask - bias
+ if exp < -1074 {
+ return Copysign(0, frac) // underflow
}
- if exp >= mask { // overflow
+ if exp > 1023 { // overflow
if frac < 0 {
return Inf(-1)
}
return Inf(1)
}
+ var m float64 = 1
+ if exp < -1022 { // denormal
+ exp += 52
+ m = 1.0 / (1 << 52) // 2**-52
+ }
x &^= mask << shift
- x |= uint64(exp) << shift
- return Float64frombits(x)
+ x |= uint64(exp+bias) << shift
+ return m * Float64frombits(x)
}
diff --git a/src/pkg/math/lgamma.go b/src/pkg/math/lgamma.go
index dc31be929..dc30f468f 100644
--- a/src/pkg/math/lgamma.go
+++ b/src/pkg/math/lgamma.go
@@ -272,7 +272,7 @@ func Lgamma(x float64) (lgamma float64, sign int) {
p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6))))))
q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6)))))
lgamma = 0.5*y + p/q
- z := float64(1) // Lgamma(1+s) = Log(s) + Lgamma(s)
+ z := 1.0 // Lgamma(1+s) = Log(s) + Lgamma(s)
switch i {
case 7:
z *= (y + 6)
diff --git a/src/pkg/math/logb.go b/src/pkg/math/logb.go
index 9e4651517..072281ddf 100644
--- a/src/pkg/math/logb.go
+++ b/src/pkg/math/logb.go
@@ -4,7 +4,7 @@
package math
-// Logb(x) returns the binary exponent of non-zero x.
+// Logb(x) returns the binary exponent of x.
//
// Special cases are:
// Logb(±Inf) = +Inf
@@ -22,10 +22,10 @@ func Logb(x float64) float64 {
case x != x: // IsNaN(x):
return x
}
- return float64(int((Float64bits(x)>>shift)&mask) - bias)
+ return float64(ilogb(x))
}
-// Ilogb(x) returns the binary exponent of non-zero x as an integer.
+// Ilogb(x) returns the binary exponent of x as an integer.
//
// Special cases are:
// Ilogb(±Inf) = MaxInt32
@@ -43,5 +43,12 @@ func Ilogb(x float64) int {
case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
return MaxInt32
}
- return int((Float64bits(x)>>shift)&mask) - bias
+ return ilogb(x)
+}
+
+// logb returns the binary exponent of x. It assumes x is finite and
+// non-zero.
+func ilogb(x float64) int {
+ x, exp := normalize(x)
+ return int((Float64bits(x)>>shift)&mask) - bias + exp
}
diff --git a/src/pkg/math/pow.go b/src/pkg/math/pow.go
index f0ad84af6..06b107401 100644
--- a/src/pkg/math/pow.go
+++ b/src/pkg/math/pow.go
@@ -98,7 +98,7 @@ func Pow(x, y float64) float64 {
}
// ans = a1 * 2**ae (= 1 for now).
- a1 := float64(1)
+ a1 := 1.0
ae := 0
// ans *= x**yf