Home | History | Annotate | Download | only in runtime
      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 
      5 package runtime_test
      6 
      7 import (
      8 	"math"
      9 	"math/rand"
     10 	. "runtime"
     11 	"testing"
     12 )
     13 
     14 // turn uint64 op into float64 op
     15 func 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 
     23 func add(x, y float64) float64 { return x + y }
     24 func sub(x, y float64) float64 { return x - y }
     25 func mul(x, y float64) float64 { return x * y }
     26 func div(x, y float64) float64 { return x / y }
     27 
     28 func 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
     88 func trunc32(f float64) float64 {
     89 	return float64(float32(f))
     90 }
     91 
     92 // 64 -sw->32 -hw-> 64
     93 func to32sw(f float64) float64 {
     94 	return float64(math.Float32frombits(F64to32(math.Float64bits(f))))
     95 }
     96 
     97 // 64 -hw->32 -sw-> 64
     98 func to64sw(f float64) float64 {
     99 	return math.Float64frombits(F32to64(math.Float32bits(float32(f))))
    100 }
    101 
    102 // float64 -hw-> int64 -hw-> float64
    103 func hwint64(f float64) float64 {
    104 	return float64(int64(f))
    105 }
    106 
    107 // float64 -hw-> int32 -hw-> float64
    108 func hwint32(f float64) float64 {
    109 	return float64(int32(f))
    110 }
    111 
    112 // float64 -sw-> int64 -hw-> float64
    113 func 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
    124 func fromint64sw(f float64) float64 {
    125 	return math.Float64frombits(Fintto64(int64(f)))
    126 }
    127 
    128 var nerr int
    129 
    130 func err(t *testing.T, format string, args ...interface{}) {
    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 
    142 func 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 
    162 func 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 
    170 func 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 
    182 func 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 
    190 func 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