| // Copyright 2010 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. |
| |
| package runtime_test |
| |
| import ( |
| "math" |
| "math/rand" |
| . "runtime" |
| "testing" |
| ) |
| |
| // turn uint64 op into float64 op |
| func fop(f func(x, y uint64) uint64) func(x, y float64) float64 { |
| return func(x, y float64) float64 { |
| bx := math.Float64bits(x) |
| by := math.Float64bits(y) |
| return math.Float64frombits(f(bx, by)) |
| } |
| } |
| |
| func add(x, y float64) float64 { return x + y } |
| func sub(x, y float64) float64 { return x - y } |
| func mul(x, y float64) float64 { return x * y } |
| func div(x, y float64) float64 { return x / y } |
| |
| func TestFloat64(t *testing.T) { |
| base := []float64{ |
| 0, |
| math.Copysign(0, -1), |
| -1, |
| 1, |
| math.NaN(), |
| math.Inf(+1), |
| math.Inf(-1), |
| 0.1, |
| 1.5, |
| 1.9999999999999998, // all 1s mantissa |
| 1.3333333333333333, // 1.010101010101... |
| 1.1428571428571428, // 1.001001001001... |
| 1.112536929253601e-308, // first normal |
| 2, |
| 4, |
| 8, |
| 16, |
| 32, |
| 64, |
| 128, |
| 256, |
| 3, |
| 12, |
| 1234, |
| 123456, |
| -0.1, |
| -1.5, |
| -1.9999999999999998, |
| -1.3333333333333333, |
| -1.1428571428571428, |
| -2, |
| -3, |
| 1e-200, |
| 1e-300, |
| 1e-310, |
| 5e-324, |
| 1e-105, |
| 1e-305, |
| 1e+200, |
| 1e+306, |
| 1e+307, |
| 1e+308, |
| } |
| all := make([]float64, 200) |
| copy(all, base) |
| for i := len(base); i < len(all); i++ { |
| all[i] = rand.NormFloat64() |
| } |
| |
| test(t, "+", add, fop(Fadd64), all) |
| test(t, "-", sub, fop(Fsub64), all) |
| if GOARCH != "386" { // 386 is not precise! |
| test(t, "*", mul, fop(Fmul64), all) |
| test(t, "/", div, fop(Fdiv64), all) |
| } |
| } |
| |
| // 64 -hw-> 32 -hw-> 64 |
| func trunc32(f float64) float64 { |
| return float64(float32(f)) |
| } |
| |
| // 64 -sw->32 -hw-> 64 |
| func to32sw(f float64) float64 { |
| return float64(math.Float32frombits(F64to32(math.Float64bits(f)))) |
| } |
| |
| // 64 -hw->32 -sw-> 64 |
| func to64sw(f float64) float64 { |
| return math.Float64frombits(F32to64(math.Float32bits(float32(f)))) |
| } |
| |
| // float64 -hw-> int64 -hw-> float64 |
| func hwint64(f float64) float64 { |
| return float64(int64(f)) |
| } |
| |
| // float64 -hw-> int32 -hw-> float64 |
| func hwint32(f float64) float64 { |
| return float64(int32(f)) |
| } |
| |
| // float64 -sw-> int64 -hw-> float64 |
| func toint64sw(f float64) float64 { |
| i, ok := F64toint(math.Float64bits(f)) |
| if !ok { |
| // There's no right answer for out of range. |
| // Match the hardware to pass the test. |
| i = int64(f) |
| } |
| return float64(i) |
| } |
| |
| // float64 -hw-> int64 -sw-> float64 |
| func fromint64sw(f float64) float64 { |
| return math.Float64frombits(Fintto64(int64(f))) |
| } |
| |
| var nerr int |
| |
| func err(t *testing.T, format string, args ...interface{}) { |
| t.Errorf(format, args...) |
| |
| // cut errors off after a while. |
| // otherwise we spend all our time |
| // allocating memory to hold the |
| // formatted output. |
| if nerr++; nerr >= 10 { |
| t.Fatal("too many errors") |
| } |
| } |
| |
| func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) { |
| for _, f := range all { |
| for _, g := range all { |
| h := hw(f, g) |
| s := sw(f, g) |
| if !same(h, s) { |
| err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h) |
| } |
| testu(t, "to32", trunc32, to32sw, h) |
| testu(t, "to64", trunc32, to64sw, h) |
| testu(t, "toint64", hwint64, toint64sw, h) |
| testu(t, "fromint64", hwint64, fromint64sw, h) |
| testcmp(t, f, h) |
| testcmp(t, h, f) |
| testcmp(t, g, h) |
| testcmp(t, h, g) |
| } |
| } |
| } |
| |
| func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) { |
| h := hw(v) |
| s := sw(v) |
| if !same(h, s) { |
| err(t, "%s %g = sw %g, hw %g\n", op, v, s, h) |
| } |
| } |
| |
| func hwcmp(f, g float64) (cmp int, isnan bool) { |
| switch { |
| case f < g: |
| return -1, false |
| case f > g: |
| return +1, false |
| case f == g: |
| return 0, false |
| } |
| return 0, true // must be NaN |
| } |
| |
| func testcmp(t *testing.T, f, g float64) { |
| hcmp, hisnan := hwcmp(f, g) |
| scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g)) |
| if int32(hcmp) != scmp || hisnan != sisnan { |
| err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan) |
| } |
| } |
| |
| func same(f, g float64) bool { |
| if math.IsNaN(f) && math.IsNaN(g) { |
| return true |
| } |
| if math.Copysign(1, f) != math.Copysign(1, g) { |
| return false |
| } |
| return f == g |
| } |