Source file src/cmd/compile/internal/test/float_test.go

     1  // Copyright 2016 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 test
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  )
    11  
    12  //go:noinline
    13  func compare1(a, b float64) bool {
    14  	return a < b
    15  }
    16  
    17  //go:noinline
    18  func compare2(a, b float32) bool {
    19  	return a < b
    20  }
    21  
    22  func TestFloatCompare(t *testing.T) {
    23  	if !compare1(3, 5) {
    24  		t.Errorf("compare1 returned false")
    25  	}
    26  	if !compare2(3, 5) {
    27  		t.Errorf("compare2 returned false")
    28  	}
    29  }
    30  
    31  func TestFloatCompareFolded(t *testing.T) {
    32  	// float64 comparisons
    33  	d1, d3, d5, d9 := float64(1), float64(3), float64(5), float64(9)
    34  	if d3 == d5 {
    35  		t.Errorf("d3 == d5 returned true")
    36  	}
    37  	if d3 != d3 {
    38  		t.Errorf("d3 != d3 returned true")
    39  	}
    40  	if d3 > d5 {
    41  		t.Errorf("d3 > d5 returned true")
    42  	}
    43  	if d3 >= d9 {
    44  		t.Errorf("d3 >= d9 returned true")
    45  	}
    46  	if d5 < d1 {
    47  		t.Errorf("d5 < d1 returned true")
    48  	}
    49  	if d9 <= d1 {
    50  		t.Errorf("d9 <= d1 returned true")
    51  	}
    52  	if math.NaN() == math.NaN() {
    53  		t.Errorf("math.NaN() == math.NaN() returned true")
    54  	}
    55  	if math.NaN() >= math.NaN() {
    56  		t.Errorf("math.NaN() >= math.NaN() returned true")
    57  	}
    58  	if math.NaN() <= math.NaN() {
    59  		t.Errorf("math.NaN() <= math.NaN() returned true")
    60  	}
    61  	if math.Copysign(math.NaN(), -1) < math.NaN() {
    62  		t.Errorf("math.Copysign(math.NaN(), -1) < math.NaN() returned true")
    63  	}
    64  	if math.Inf(1) != math.Inf(1) {
    65  		t.Errorf("math.Inf(1) != math.Inf(1) returned true")
    66  	}
    67  	if math.Inf(-1) != math.Inf(-1) {
    68  		t.Errorf("math.Inf(-1) != math.Inf(-1) returned true")
    69  	}
    70  	if math.Copysign(0, -1) != 0 {
    71  		t.Errorf("math.Copysign(0, -1) != 0 returned true")
    72  	}
    73  	if math.Copysign(0, -1) < 0 {
    74  		t.Errorf("math.Copysign(0, -1) < 0 returned true")
    75  	}
    76  	if 0 > math.Copysign(0, -1) {
    77  		t.Errorf("0 > math.Copysign(0, -1) returned true")
    78  	}
    79  
    80  	// float32 comparisons
    81  	s1, s3, s5, s9 := float32(1), float32(3), float32(5), float32(9)
    82  	if s3 == s5 {
    83  		t.Errorf("s3 == s5 returned true")
    84  	}
    85  	if s3 != s3 {
    86  		t.Errorf("s3 != s3 returned true")
    87  	}
    88  	if s3 > s5 {
    89  		t.Errorf("s3 > s5 returned true")
    90  	}
    91  	if s3 >= s9 {
    92  		t.Errorf("s3 >= s9 returned true")
    93  	}
    94  	if s5 < s1 {
    95  		t.Errorf("s5 < s1 returned true")
    96  	}
    97  	if s9 <= s1 {
    98  		t.Errorf("s9 <= s1 returned true")
    99  	}
   100  	sPosNaN, sNegNaN := float32(math.NaN()), float32(math.Copysign(math.NaN(), -1))
   101  	if sPosNaN == sPosNaN {
   102  		t.Errorf("sPosNaN == sPosNaN returned true")
   103  	}
   104  	if sPosNaN >= sPosNaN {
   105  		t.Errorf("sPosNaN >= sPosNaN returned true")
   106  	}
   107  	if sPosNaN <= sPosNaN {
   108  		t.Errorf("sPosNaN <= sPosNaN returned true")
   109  	}
   110  	if sNegNaN < sPosNaN {
   111  		t.Errorf("sNegNaN < sPosNaN returned true")
   112  	}
   113  	sPosInf, sNegInf := float32(math.Inf(1)), float32(math.Inf(-1))
   114  	if sPosInf != sPosInf {
   115  		t.Errorf("sPosInf != sPosInf returned true")
   116  	}
   117  	if sNegInf != sNegInf {
   118  		t.Errorf("sNegInf != sNegInf returned true")
   119  	}
   120  	sNegZero := float32(math.Copysign(0, -1))
   121  	if sNegZero != 0 {
   122  		t.Errorf("sNegZero != 0 returned true")
   123  	}
   124  	if sNegZero < 0 {
   125  		t.Errorf("sNegZero < 0 returned true")
   126  	}
   127  	if 0 > sNegZero {
   128  		t.Errorf("0 > sNegZero returned true")
   129  	}
   130  }
   131  
   132  //go:noinline
   133  func cvt1(a float64) uint64 {
   134  	return uint64(a)
   135  }
   136  
   137  //go:noinline
   138  func cvt2(a float64) uint32 {
   139  	return uint32(a)
   140  }
   141  
   142  //go:noinline
   143  func cvt3(a float32) uint64 {
   144  	return uint64(a)
   145  }
   146  
   147  //go:noinline
   148  func cvt4(a float32) uint32 {
   149  	return uint32(a)
   150  }
   151  
   152  //go:noinline
   153  func cvt5(a float64) int64 {
   154  	return int64(a)
   155  }
   156  
   157  //go:noinline
   158  func cvt6(a float64) int32 {
   159  	return int32(a)
   160  }
   161  
   162  //go:noinline
   163  func cvt7(a float32) int64 {
   164  	return int64(a)
   165  }
   166  
   167  //go:noinline
   168  func cvt8(a float32) int32 {
   169  	return int32(a)
   170  }
   171  
   172  // make sure to cover int, uint cases (issue #16738)
   173  //
   174  //go:noinline
   175  func cvt9(a float64) int {
   176  	return int(a)
   177  }
   178  
   179  //go:noinline
   180  func cvt10(a float64) uint {
   181  	return uint(a)
   182  }
   183  
   184  //go:noinline
   185  func cvt11(a float32) int {
   186  	return int(a)
   187  }
   188  
   189  //go:noinline
   190  func cvt12(a float32) uint {
   191  	return uint(a)
   192  }
   193  
   194  //go:noinline
   195  func f2i64p(v float64) *int64 {
   196  	return ip64(int64(v / 0.1))
   197  }
   198  
   199  //go:noinline
   200  func ip64(v int64) *int64 {
   201  	return &v
   202  }
   203  
   204  func TestFloatConvert(t *testing.T) {
   205  	if got := cvt1(3.5); got != 3 {
   206  		t.Errorf("cvt1 got %d, wanted 3", got)
   207  	}
   208  	if got := cvt2(3.5); got != 3 {
   209  		t.Errorf("cvt2 got %d, wanted 3", got)
   210  	}
   211  	if got := cvt3(3.5); got != 3 {
   212  		t.Errorf("cvt3 got %d, wanted 3", got)
   213  	}
   214  	if got := cvt4(3.5); got != 3 {
   215  		t.Errorf("cvt4 got %d, wanted 3", got)
   216  	}
   217  	if got := cvt5(3.5); got != 3 {
   218  		t.Errorf("cvt5 got %d, wanted 3", got)
   219  	}
   220  	if got := cvt6(3.5); got != 3 {
   221  		t.Errorf("cvt6 got %d, wanted 3", got)
   222  	}
   223  	if got := cvt7(3.5); got != 3 {
   224  		t.Errorf("cvt7 got %d, wanted 3", got)
   225  	}
   226  	if got := cvt8(3.5); got != 3 {
   227  		t.Errorf("cvt8 got %d, wanted 3", got)
   228  	}
   229  	if got := cvt9(3.5); got != 3 {
   230  		t.Errorf("cvt9 got %d, wanted 3", got)
   231  	}
   232  	if got := cvt10(3.5); got != 3 {
   233  		t.Errorf("cvt10 got %d, wanted 3", got)
   234  	}
   235  	if got := cvt11(3.5); got != 3 {
   236  		t.Errorf("cvt11 got %d, wanted 3", got)
   237  	}
   238  	if got := cvt12(3.5); got != 3 {
   239  		t.Errorf("cvt12 got %d, wanted 3", got)
   240  	}
   241  	if got := *f2i64p(10); got != 100 {
   242  		t.Errorf("f2i64p got %d, wanted 100", got)
   243  	}
   244  }
   245  
   246  func TestFloatConvertFolded(t *testing.T) {
   247  	// Assign constants to variables so that they are (hopefully) constant folded
   248  	// by the SSA backend rather than the frontend.
   249  	u64, u32, u16, u8 := uint64(1<<63), uint32(1<<31), uint16(1<<15), uint8(1<<7)
   250  	i64, i32, i16, i8 := int64(-1<<63), int32(-1<<31), int16(-1<<15), int8(-1<<7)
   251  	du64, du32, du16, du8 := float64(1<<63), float64(1<<31), float64(1<<15), float64(1<<7)
   252  	di64, di32, di16, di8 := float64(-1<<63), float64(-1<<31), float64(-1<<15), float64(-1<<7)
   253  	su64, su32, su16, su8 := float32(1<<63), float32(1<<31), float32(1<<15), float32(1<<7)
   254  	si64, si32, si16, si8 := float32(-1<<63), float32(-1<<31), float32(-1<<15), float32(-1<<7)
   255  
   256  	// integer to float
   257  	if float64(u64) != du64 {
   258  		t.Errorf("float64(u64) != du64")
   259  	}
   260  	if float64(u32) != du32 {
   261  		t.Errorf("float64(u32) != du32")
   262  	}
   263  	if float64(u16) != du16 {
   264  		t.Errorf("float64(u16) != du16")
   265  	}
   266  	if float64(u8) != du8 {
   267  		t.Errorf("float64(u8) != du8")
   268  	}
   269  	if float64(i64) != di64 {
   270  		t.Errorf("float64(i64) != di64")
   271  	}
   272  	if float64(i32) != di32 {
   273  		t.Errorf("float64(i32) != di32")
   274  	}
   275  	if float64(i16) != di16 {
   276  		t.Errorf("float64(i16) != di16")
   277  	}
   278  	if float64(i8) != di8 {
   279  		t.Errorf("float64(i8) != di8")
   280  	}
   281  	if float32(u64) != su64 {
   282  		t.Errorf("float32(u64) != su64")
   283  	}
   284  	if float32(u32) != su32 {
   285  		t.Errorf("float32(u32) != su32")
   286  	}
   287  	if float32(u16) != su16 {
   288  		t.Errorf("float32(u16) != su16")
   289  	}
   290  	if float32(u8) != su8 {
   291  		t.Errorf("float32(u8) != su8")
   292  	}
   293  	if float32(i64) != si64 {
   294  		t.Errorf("float32(i64) != si64")
   295  	}
   296  	if float32(i32) != si32 {
   297  		t.Errorf("float32(i32) != si32")
   298  	}
   299  	if float32(i16) != si16 {
   300  		t.Errorf("float32(i16) != si16")
   301  	}
   302  	if float32(i8) != si8 {
   303  		t.Errorf("float32(i8) != si8")
   304  	}
   305  
   306  	// float to integer
   307  	if uint64(du64) != u64 {
   308  		t.Errorf("uint64(du64) != u64")
   309  	}
   310  	if uint32(du32) != u32 {
   311  		t.Errorf("uint32(du32) != u32")
   312  	}
   313  	if uint16(du16) != u16 {
   314  		t.Errorf("uint16(du16) != u16")
   315  	}
   316  	if uint8(du8) != u8 {
   317  		t.Errorf("uint8(du8) != u8")
   318  	}
   319  	if int64(di64) != i64 {
   320  		t.Errorf("int64(di64) != i64")
   321  	}
   322  	if int32(di32) != i32 {
   323  		t.Errorf("int32(di32) != i32")
   324  	}
   325  	if int16(di16) != i16 {
   326  		t.Errorf("int16(di16) != i16")
   327  	}
   328  	if int8(di8) != i8 {
   329  		t.Errorf("int8(di8) != i8")
   330  	}
   331  	if uint64(su64) != u64 {
   332  		t.Errorf("uint64(su64) != u64")
   333  	}
   334  	if uint32(su32) != u32 {
   335  		t.Errorf("uint32(su32) != u32")
   336  	}
   337  	if uint16(su16) != u16 {
   338  		t.Errorf("uint16(su16) != u16")
   339  	}
   340  	if uint8(su8) != u8 {
   341  		t.Errorf("uint8(su8) != u8")
   342  	}
   343  	if int64(si64) != i64 {
   344  		t.Errorf("int64(si64) != i64")
   345  	}
   346  	if int32(si32) != i32 {
   347  		t.Errorf("int32(si32) != i32")
   348  	}
   349  	if int16(si16) != i16 {
   350  		t.Errorf("int16(si16) != i16")
   351  	}
   352  	if int8(si8) != i8 {
   353  		t.Errorf("int8(si8) != i8")
   354  	}
   355  }
   356  
   357  func TestFloat32StoreToLoadConstantFold(t *testing.T) {
   358  	// Test that math.Float32{,from}bits constant fold correctly.
   359  	// In particular we need to be careful that signaling NaN (sNaN) values
   360  	// are not converted to quiet NaN (qNaN) values during compilation.
   361  	// See issue #27193 for more information.
   362  
   363  	// signaling NaNs
   364  	{
   365  		const nan = uint32(0x7f800001) // sNaN
   366  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   367  			t.Errorf("got %#x, want %#x", x, nan)
   368  		}
   369  	}
   370  	{
   371  		const nan = uint32(0x7fbfffff) // sNaN
   372  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   373  			t.Errorf("got %#x, want %#x", x, nan)
   374  		}
   375  	}
   376  	{
   377  		const nan = uint32(0xff800001) // sNaN
   378  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   379  			t.Errorf("got %#x, want %#x", x, nan)
   380  		}
   381  	}
   382  	{
   383  		const nan = uint32(0xffbfffff) // sNaN
   384  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   385  			t.Errorf("got %#x, want %#x", x, nan)
   386  		}
   387  	}
   388  
   389  	// quiet NaNs
   390  	{
   391  		const nan = uint32(0x7fc00000) // qNaN
   392  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   393  			t.Errorf("got %#x, want %#x", x, nan)
   394  		}
   395  	}
   396  	{
   397  		const nan = uint32(0x7fffffff) // qNaN
   398  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   399  			t.Errorf("got %#x, want %#x", x, nan)
   400  		}
   401  	}
   402  	{
   403  		const nan = uint32(0x8fc00000) // qNaN
   404  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   405  			t.Errorf("got %#x, want %#x", x, nan)
   406  		}
   407  	}
   408  	{
   409  		const nan = uint32(0x8fffffff) // qNaN
   410  		if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
   411  			t.Errorf("got %#x, want %#x", x, nan)
   412  		}
   413  	}
   414  
   415  	// infinities
   416  	{
   417  		const inf = uint32(0x7f800000) // +∞
   418  		if x := math.Float32bits(math.Float32frombits(inf)); x != inf {
   419  			t.Errorf("got %#x, want %#x", x, inf)
   420  		}
   421  	}
   422  	{
   423  		const negInf = uint32(0xff800000) // -∞
   424  		if x := math.Float32bits(math.Float32frombits(negInf)); x != negInf {
   425  			t.Errorf("got %#x, want %#x", x, negInf)
   426  		}
   427  	}
   428  
   429  	// numbers
   430  	{
   431  		const zero = uint32(0) // +0.0
   432  		if x := math.Float32bits(math.Float32frombits(zero)); x != zero {
   433  			t.Errorf("got %#x, want %#x", x, zero)
   434  		}
   435  	}
   436  	{
   437  		const negZero = uint32(1 << 31) // -0.0
   438  		if x := math.Float32bits(math.Float32frombits(negZero)); x != negZero {
   439  			t.Errorf("got %#x, want %#x", x, negZero)
   440  		}
   441  	}
   442  	{
   443  		const one = uint32(0x3f800000) // 1.0
   444  		if x := math.Float32bits(math.Float32frombits(one)); x != one {
   445  			t.Errorf("got %#x, want %#x", x, one)
   446  		}
   447  	}
   448  	{
   449  		const negOne = uint32(0xbf800000) // -1.0
   450  		if x := math.Float32bits(math.Float32frombits(negOne)); x != negOne {
   451  			t.Errorf("got %#x, want %#x", x, negOne)
   452  		}
   453  	}
   454  	{
   455  		const frac = uint32(0x3fc00000) // +1.5
   456  		if x := math.Float32bits(math.Float32frombits(frac)); x != frac {
   457  			t.Errorf("got %#x, want %#x", x, frac)
   458  		}
   459  	}
   460  	{
   461  		const negFrac = uint32(0xbfc00000) // -1.5
   462  		if x := math.Float32bits(math.Float32frombits(negFrac)); x != negFrac {
   463  			t.Errorf("got %#x, want %#x", x, negFrac)
   464  		}
   465  	}
   466  }
   467  
   468  // Signaling NaN values as constants.
   469  const (
   470  	snan32bits uint32 = 0x7f800001
   471  	snan64bits uint64 = 0x7ff0000000000001
   472  )
   473  
   474  // Signaling NaNs as variables.
   475  var snan32bitsVar uint32 = snan32bits
   476  var snan64bitsVar uint64 = snan64bits
   477  
   478  func TestFloatSignalingNaN(t *testing.T) {
   479  	// Make sure we generate a signaling NaN from a constant properly.
   480  	// See issue 36400.
   481  	f32 := math.Float32frombits(snan32bits)
   482  	g32 := math.Float32frombits(snan32bitsVar)
   483  	x32 := math.Float32bits(f32)
   484  	y32 := math.Float32bits(g32)
   485  	if x32 != y32 {
   486  		t.Errorf("got %x, want %x (diff=%x)", x32, y32, x32^y32)
   487  	}
   488  
   489  	f64 := math.Float64frombits(snan64bits)
   490  	g64 := math.Float64frombits(snan64bitsVar)
   491  	x64 := math.Float64bits(f64)
   492  	y64 := math.Float64bits(g64)
   493  	if x64 != y64 {
   494  		t.Errorf("got %x, want %x (diff=%x)", x64, y64, x64^y64)
   495  	}
   496  }
   497  
   498  func TestFloatSignalingNaNConversion(t *testing.T) {
   499  	// Test to make sure when we convert a signaling NaN, we get a NaN.
   500  	// (Ideally we want a quiet NaN, but some platforms don't agree.)
   501  	// See issue 36399.
   502  	s32 := math.Float32frombits(snan32bitsVar)
   503  	if s32 == s32 {
   504  		t.Errorf("converting a NaN did not result in a NaN")
   505  	}
   506  	s64 := math.Float64frombits(snan64bitsVar)
   507  	if s64 == s64 {
   508  		t.Errorf("converting a NaN did not result in a NaN")
   509  	}
   510  }
   511  
   512  func TestFloatSignalingNaNConversionConst(t *testing.T) {
   513  	// Test to make sure when we convert a signaling NaN, it converts to a NaN.
   514  	// (Ideally we want a quiet NaN, but some platforms don't agree.)
   515  	// See issue 36399 and 36400.
   516  	s32 := math.Float32frombits(snan32bits)
   517  	if s32 == s32 {
   518  		t.Errorf("converting a NaN did not result in a NaN")
   519  	}
   520  	s64 := math.Float64frombits(snan64bits)
   521  	if s64 == s64 {
   522  		t.Errorf("converting a NaN did not result in a NaN")
   523  	}
   524  }
   525  
   526  //go:noinline
   527  func isPosInf(x float64) bool {
   528  	return math.IsInf(x, 1)
   529  }
   530  
   531  //go:noinline
   532  func isPosInfEq(x float64) bool {
   533  	return x == math.Inf(1)
   534  }
   535  
   536  //go:noinline
   537  func isPosInfCmp(x float64) bool {
   538  	return x > math.MaxFloat64
   539  }
   540  
   541  //go:noinline
   542  func isNotPosInf(x float64) bool {
   543  	return !math.IsInf(x, 1)
   544  }
   545  
   546  //go:noinline
   547  func isNotPosInfEq(x float64) bool {
   548  	return x != math.Inf(1)
   549  }
   550  
   551  //go:noinline
   552  func isNotPosInfCmp(x float64) bool {
   553  	return x <= math.MaxFloat64
   554  }
   555  
   556  //go:noinline
   557  func isNegInf(x float64) bool {
   558  	return math.IsInf(x, -1)
   559  }
   560  
   561  //go:noinline
   562  func isNegInfEq(x float64) bool {
   563  	return x == math.Inf(-1)
   564  }
   565  
   566  //go:noinline
   567  func isNegInfCmp(x float64) bool {
   568  	return x < -math.MaxFloat64
   569  }
   570  
   571  //go:noinline
   572  func isNotNegInf(x float64) bool {
   573  	return !math.IsInf(x, -1)
   574  }
   575  
   576  //go:noinline
   577  func isNotNegInfEq(x float64) bool {
   578  	return x != math.Inf(-1)
   579  }
   580  
   581  //go:noinline
   582  func isNotNegInfCmp(x float64) bool {
   583  	return x >= -math.MaxFloat64
   584  }
   585  
   586  func TestInf(t *testing.T) {
   587  	tests := []struct {
   588  		value    float64
   589  		isPosInf bool
   590  		isNegInf bool
   591  		isNaN    bool
   592  	}{
   593  		{value: math.Inf(1), isPosInf: true},
   594  		{value: math.MaxFloat64},
   595  		{value: math.Inf(-1), isNegInf: true},
   596  		{value: -math.MaxFloat64},
   597  		{value: math.NaN(), isNaN: true},
   598  	}
   599  
   600  	check := func(name string, f func(x float64) bool, value float64, want bool) {
   601  		got := f(value)
   602  		if got != want {
   603  			t.Errorf("%v(%g): want %v, got %v", name, value, want, got)
   604  		}
   605  	}
   606  
   607  	for _, test := range tests {
   608  		check("isPosInf", isPosInf, test.value, test.isPosInf)
   609  		check("isPosInfEq", isPosInfEq, test.value, test.isPosInf)
   610  		check("isPosInfCmp", isPosInfCmp, test.value, test.isPosInf)
   611  
   612  		check("isNotPosInf", isNotPosInf, test.value, !test.isPosInf)
   613  		check("isNotPosInfEq", isNotPosInfEq, test.value, !test.isPosInf)
   614  		check("isNotPosInfCmp", isNotPosInfCmp, test.value, !test.isPosInf && !test.isNaN)
   615  
   616  		check("isNegInf", isNegInf, test.value, test.isNegInf)
   617  		check("isNegInfEq", isNegInfEq, test.value, test.isNegInf)
   618  		check("isNegInfCmp", isNegInfCmp, test.value, test.isNegInf)
   619  
   620  		check("isNotNegInf", isNotNegInf, test.value, !test.isNegInf)
   621  		check("isNotNegInfEq", isNotNegInfEq, test.value, !test.isNegInf)
   622  		check("isNotNegInfCmp", isNotNegInfCmp, test.value, !test.isNegInf && !test.isNaN)
   623  	}
   624  }
   625  
   626  //go:noinline
   627  func isNaNOrGtZero64(x float64) bool {
   628  	return math.IsNaN(x) || x > 0
   629  }
   630  
   631  //go:noinline
   632  func isNaNOrGteZero64(x float64) bool {
   633  	return x >= 0 || math.IsNaN(x)
   634  }
   635  
   636  //go:noinline
   637  func isNaNOrLtZero64(x float64) bool {
   638  	return x < 0 || math.IsNaN(x)
   639  }
   640  
   641  //go:noinline
   642  func isNaNOrLteZero64(x float64) bool {
   643  	return math.IsNaN(x) || x <= 0
   644  }
   645  
   646  func TestFusedNaNChecks64(t *testing.T) {
   647  	tests := []struct {
   648  		value             float64
   649  		isZero            bool
   650  		isGreaterThanZero bool
   651  		isLessThanZero    bool
   652  		isNaN             bool
   653  	}{
   654  		{value: 0.0, isZero: true},
   655  		{value: math.Copysign(0, -1), isZero: true},
   656  		{value: 1.0, isGreaterThanZero: true},
   657  		{value: -1.0, isLessThanZero: true},
   658  		{value: math.Inf(1), isGreaterThanZero: true},
   659  		{value: math.Inf(-1), isLessThanZero: true},
   660  		{value: math.NaN(), isNaN: true},
   661  	}
   662  
   663  	check := func(name string, f func(x float64) bool, value float64, want bool) {
   664  		got := f(value)
   665  		if got != want {
   666  			t.Errorf("%v(%g): want %v, got %v", name, value, want, got)
   667  		}
   668  	}
   669  
   670  	for _, test := range tests {
   671  		check("isNaNOrGtZero64", isNaNOrGtZero64, test.value, test.isNaN || test.isGreaterThanZero)
   672  		check("isNaNOrGteZero64", isNaNOrGteZero64, test.value, test.isNaN || test.isGreaterThanZero || test.isZero)
   673  		check("isNaNOrLtZero64", isNaNOrLtZero64, test.value, test.isNaN || test.isLessThanZero)
   674  		check("isNaNOrLteZero64", isNaNOrLteZero64, test.value, test.isNaN || test.isLessThanZero || test.isZero)
   675  	}
   676  }
   677  
   678  //go:noinline
   679  func isNaNOrGtZero32(x float32) bool {
   680  	return x > 0 || x != x
   681  }
   682  
   683  //go:noinline
   684  func isNaNOrGteZero32(x float32) bool {
   685  	return x != x || x >= 0
   686  }
   687  
   688  //go:noinline
   689  func isNaNOrLtZero32(x float32) bool {
   690  	return x != x || x < 0
   691  }
   692  
   693  //go:noinline
   694  func isNaNOrLteZero32(x float32) bool {
   695  	return x <= 0 || x != x
   696  }
   697  
   698  func TestFusedNaNChecks32(t *testing.T) {
   699  	tests := []struct {
   700  		value             float32
   701  		isZero            bool
   702  		isGreaterThanZero bool
   703  		isLessThanZero    bool
   704  		isNaN             bool
   705  	}{
   706  		{value: 0.0, isZero: true},
   707  		{value: float32(math.Copysign(0, -1)), isZero: true},
   708  		{value: 1.0, isGreaterThanZero: true},
   709  		{value: -1.0, isLessThanZero: true},
   710  		{value: float32(math.Inf(1)), isGreaterThanZero: true},
   711  		{value: float32(math.Inf(-1)), isLessThanZero: true},
   712  		{value: float32(math.NaN()), isNaN: true},
   713  	}
   714  
   715  	check := func(name string, f func(x float32) bool, value float32, want bool) {
   716  		got := f(value)
   717  		if got != want {
   718  			t.Errorf("%v(%g): want %v, got %v", name, value, want, got)
   719  		}
   720  	}
   721  
   722  	for _, test := range tests {
   723  		check("isNaNOrGtZero32", isNaNOrGtZero32, test.value, test.isNaN || test.isGreaterThanZero)
   724  		check("isNaNOrGteZero32", isNaNOrGteZero32, test.value, test.isNaN || test.isGreaterThanZero || test.isZero)
   725  		check("isNaNOrLtZero32", isNaNOrLtZero32, test.value, test.isNaN || test.isLessThanZero)
   726  		check("isNaNOrLteZero32", isNaNOrLteZero32, test.value, test.isNaN || test.isLessThanZero || test.isZero)
   727  	}
   728  }
   729  
   730  // minNormal64 is the smallest float64 value that is not subnormal.
   731  const minNormal64 = 2.2250738585072014e-308
   732  
   733  //go:noinline
   734  func isAbsLessThanMinNormal64(x float64) bool {
   735  	return math.Abs(x) < minNormal64
   736  }
   737  
   738  //go:noinline
   739  func isLessThanMinNormal64(x float64) bool {
   740  	return x < minNormal64
   741  }
   742  
   743  //go:noinline
   744  func isGreaterThanNegMinNormal64(x float64) bool {
   745  	return x > -minNormal64
   746  }
   747  
   748  //go:noinline
   749  func isGreaterThanOrEqualToMinNormal64(x float64) bool {
   750  	return math.Abs(x) >= minNormal64
   751  }
   752  
   753  func TestSubnormalComparisons(t *testing.T) {
   754  	tests := []struct {
   755  		value                  float64
   756  		isAbsLessThanMinNormal bool
   757  		isPositive             bool
   758  		isNegative             bool
   759  		isNaN                  bool
   760  	}{
   761  		{value: math.Inf(1), isPositive: true},
   762  		{value: math.MaxFloat64, isPositive: true},
   763  		{value: math.Inf(-1), isNegative: true},
   764  		{value: -math.MaxFloat64, isNegative: true},
   765  		{value: math.NaN(), isNaN: true},
   766  		{value: minNormal64, isPositive: true},
   767  		{value: minNormal64 / 2, isAbsLessThanMinNormal: true, isPositive: true},
   768  		{value: -minNormal64, isNegative: true},
   769  		{value: -minNormal64 / 2, isAbsLessThanMinNormal: true, isNegative: true},
   770  		{value: 0, isAbsLessThanMinNormal: true, isPositive: true},
   771  		{value: math.Copysign(0, -1), isAbsLessThanMinNormal: true, isNegative: true},
   772  	}
   773  
   774  	check := func(name string, f func(x float64) bool, value float64, want bool) {
   775  		got := f(value)
   776  		if got != want {
   777  			t.Errorf("%v(%g): want %v, got %v", name, value, want, got)
   778  		}
   779  	}
   780  
   781  	for _, test := range tests {
   782  		check("isAbsLessThanMinNormal64", isAbsLessThanMinNormal64, test.value, test.isAbsLessThanMinNormal)
   783  		check("isLessThanMinNormal64", isLessThanMinNormal64, test.value, test.isAbsLessThanMinNormal || test.isNegative)
   784  		check("isGreaterThanNegMinNormal64", isGreaterThanNegMinNormal64, test.value, test.isAbsLessThanMinNormal || test.isPositive)
   785  		check("isGreaterThanOrEqualToMinNormal64", isGreaterThanOrEqualToMinNormal64, test.value, !test.isAbsLessThanMinNormal && !test.isNaN)
   786  	}
   787  }
   788  
   789  var sinkFloat float64
   790  
   791  func BenchmarkMul2(b *testing.B) {
   792  	for i := 0; i < b.N; i++ {
   793  		var m float64 = 1
   794  		for j := 0; j < 500; j++ {
   795  			m *= 2
   796  		}
   797  		sinkFloat = m
   798  	}
   799  }
   800  func BenchmarkMulNeg2(b *testing.B) {
   801  	for i := 0; i < b.N; i++ {
   802  		var m float64 = 1
   803  		for j := 0; j < 500; j++ {
   804  			m *= -2
   805  		}
   806  		sinkFloat = m
   807  	}
   808  }
   809  

View as plain text