1// Copyright 2010 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package runtime_test 6 7import ( 8 "math" 9 "math/rand" 10 . "runtime" 11 "testing" 12) 13 14// turn uint64 op into float64 op 15func fop(f func(x, y uint64) uint64) func(x, y float64) float64 { 16 return func(x, y float64) float64 { 17 bx := math.Float64bits(x) 18 by := math.Float64bits(y) 19 return math.Float64frombits(f(bx, by)) 20 } 21} 22 23func add(x, y float64) float64 { return x + y } 24func sub(x, y float64) float64 { return x - y } 25func mul(x, y float64) float64 { return x * y } 26func div(x, y float64) float64 { return x / y } 27 28func TestFloat64(t *testing.T) { 29 base := []float64{ 30 0, 31 math.Copysign(0, -1), 32 -1, 33 1, 34 math.NaN(), 35 math.Inf(+1), 36 math.Inf(-1), 37 0.1, 38 1.5, 39 1.9999999999999998, // all 1s mantissa 40 1.3333333333333333, // 1.010101010101... 41 1.1428571428571428, // 1.001001001001... 42 1.112536929253601e-308, // first normal 43 2, 44 4, 45 8, 46 16, 47 32, 48 64, 49 128, 50 256, 51 3, 52 12, 53 1234, 54 123456, 55 -0.1, 56 -1.5, 57 -1.9999999999999998, 58 -1.3333333333333333, 59 -1.1428571428571428, 60 -2, 61 -3, 62 1e-200, 63 1e-300, 64 1e-310, 65 5e-324, 66 1e-105, 67 1e-305, 68 1e+200, 69 1e+306, 70 1e+307, 71 1e+308, 72 } 73 all := make([]float64, 200) 74 copy(all, base) 75 for i := len(base); i < len(all); i++ { 76 all[i] = rand.NormFloat64() 77 } 78 79 test(t, "+", add, fop(Fadd64), all) 80 test(t, "-", sub, fop(Fsub64), all) 81 if GOARCH != "386" { // 386 is not precise! 82 test(t, "*", mul, fop(Fmul64), all) 83 test(t, "/", div, fop(Fdiv64), all) 84 } 85} 86 87// 64 -hw-> 32 -hw-> 64 88func trunc32(f float64) float64 { 89 return float64(float32(f)) 90} 91 92// 64 -sw->32 -hw-> 64 93func to32sw(f float64) float64 { 94 return float64(math.Float32frombits(F64to32(math.Float64bits(f)))) 95} 96 97// 64 -hw->32 -sw-> 64 98func to64sw(f float64) float64 { 99 return math.Float64frombits(F32to64(math.Float32bits(float32(f)))) 100} 101 102// float64 -hw-> int64 -hw-> float64 103func hwint64(f float64) float64 { 104 return float64(int64(f)) 105} 106 107// float64 -hw-> int32 -hw-> float64 108func hwint32(f float64) float64 { 109 return float64(int32(f)) 110} 111 112// float64 -sw-> int64 -hw-> float64 113func toint64sw(f float64) float64 { 114 i, ok := F64toint(math.Float64bits(f)) 115 if !ok { 116 // There's no right answer for out of range. 117 // Match the hardware to pass the test. 118 i = int64(f) 119 } 120 return float64(i) 121} 122 123// float64 -hw-> int64 -sw-> float64 124func fromint64sw(f float64) float64 { 125 return math.Float64frombits(Fintto64(int64(f))) 126} 127 128var nerr int 129 130func err(t *testing.T, format string, args ...any) { 131 t.Errorf(format, args...) 132 133 // cut errors off after a while. 134 // otherwise we spend all our time 135 // allocating memory to hold the 136 // formatted output. 137 if nerr++; nerr >= 10 { 138 t.Fatal("too many errors") 139 } 140} 141 142func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) { 143 for _, f := range all { 144 for _, g := range all { 145 h := hw(f, g) 146 s := sw(f, g) 147 if !same(h, s) { 148 err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h) 149 } 150 testu(t, "to32", trunc32, to32sw, h) 151 testu(t, "to64", trunc32, to64sw, h) 152 testu(t, "toint64", hwint64, toint64sw, h) 153 testu(t, "fromint64", hwint64, fromint64sw, h) 154 testcmp(t, f, h) 155 testcmp(t, h, f) 156 testcmp(t, g, h) 157 testcmp(t, h, g) 158 } 159 } 160} 161 162func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) { 163 h := hw(v) 164 s := sw(v) 165 if !same(h, s) { 166 err(t, "%s %g = sw %g, hw %g\n", op, v, s, h) 167 } 168} 169 170func hwcmp(f, g float64) (cmp int, isnan bool) { 171 switch { 172 case f < g: 173 return -1, false 174 case f > g: 175 return +1, false 176 case f == g: 177 return 0, false 178 } 179 return 0, true // must be NaN 180} 181 182func testcmp(t *testing.T, f, g float64) { 183 hcmp, hisnan := hwcmp(f, g) 184 scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g)) 185 if int32(hcmp) != scmp || hisnan != sisnan { 186 err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan) 187 } 188} 189 190func same(f, g float64) bool { 191 if math.IsNaN(f) && math.IsNaN(g) { 192 return true 193 } 194 if math.Copysign(1, f) != math.Copysign(1, g) { 195 return false 196 } 197 return f == g 198} 199