github.com/gopherd/gonum@v0.0.4/floats/scalar/scalar_test.go (about)

     1  // Copyright ©2013 The Gonum Authors. All rights reserved.
     2  // Use of this code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package scalar
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  )
    11  
    12  func TestEqualsRelative(t *testing.T) {
    13  	t.Parallel()
    14  	equalityTests := []struct {
    15  		a, b  float64
    16  		tol   float64
    17  		equal bool
    18  	}{
    19  		{1000000, 1000001, 0, true},
    20  		{1000001, 1000000, 0, true},
    21  		{10000, 10001, 0, false},
    22  		{10001, 10000, 0, false},
    23  		{-1000000, -1000001, 0, true},
    24  		{-1000001, -1000000, 0, true},
    25  		{-10000, -10001, 0, false},
    26  		{-10001, -10000, 0, false},
    27  		{1.0000001, 1.0000002, 0, true},
    28  		{1.0000002, 1.0000001, 0, true},
    29  		{1.0002, 1.0001, 0, false},
    30  		{1.0001, 1.0002, 0, false},
    31  		{-1.000001, -1.000002, 0, true},
    32  		{-1.000002, -1.000001, 0, true},
    33  		{-1.0001, -1.0002, 0, false},
    34  		{-1.0002, -1.0001, 0, false},
    35  		{0.000000001000001, 0.000000001000002, 0, true},
    36  		{0.000000001000002, 0.000000001000001, 0, true},
    37  		{0.000000000001002, 0.000000000001001, 0, false},
    38  		{0.000000000001001, 0.000000000001002, 0, false},
    39  		{-0.000000001000001, -0.000000001000002, 0, true},
    40  		{-0.000000001000002, -0.000000001000001, 0, true},
    41  		{-0.000000000001002, -0.000000000001001, 0, false},
    42  		{-0.000000000001001, -0.000000000001002, 0, false},
    43  		{0, 0, 0, true},
    44  		{0, -0, 0, true},
    45  		{-0, -0, 0, true},
    46  		{0.00000001, 0, 0, false},
    47  		{0, 0.00000001, 0, false},
    48  		{-0.00000001, 0, 0, false},
    49  		{0, -0.00000001, 0, false},
    50  		{0, 1e-310, 0.01, true},
    51  		{1e-310, 0, 0.01, true},
    52  		{1e-310, 0, 0.000001, false},
    53  		{0, 1e-310, 0.000001, false},
    54  		{0, -1e-310, 0.1, true},
    55  		{-1e-310, 0, 0.1, true},
    56  		{-1e-310, 0, 0.00000001, false},
    57  		{0, -1e-310, 0.00000001, false},
    58  		{math.Inf(1), math.Inf(1), 0, true},
    59  		{math.Inf(-1), math.Inf(-1), 0, true},
    60  		{math.Inf(-1), math.Inf(1), 0, false},
    61  		{math.Inf(1), math.MaxFloat64, 0, false},
    62  		{math.Inf(-1), -math.MaxFloat64, 0, false},
    63  		{math.NaN(), math.NaN(), 0, false},
    64  		{math.NaN(), 0, 0, false},
    65  		{-0, math.NaN(), 0, false},
    66  		{math.NaN(), -0, 0, false},
    67  		{0, math.NaN(), 0, false},
    68  		{math.NaN(), math.Inf(1), 0, false},
    69  		{math.Inf(1), math.NaN(), 0, false},
    70  		{math.NaN(), math.Inf(-1), 0, false},
    71  		{math.Inf(-1), math.NaN(), 0, false},
    72  		{math.NaN(), math.MaxFloat64, 0, false},
    73  		{math.MaxFloat64, math.NaN(), 0, false},
    74  		{math.NaN(), -math.MaxFloat64, 0, false},
    75  		{-math.MaxFloat64, math.NaN(), 0, false},
    76  		{math.NaN(), math.SmallestNonzeroFloat64, 0, false},
    77  		{math.SmallestNonzeroFloat64, math.NaN(), 0, false},
    78  		{math.NaN(), -math.SmallestNonzeroFloat64, 0, false},
    79  		{-math.SmallestNonzeroFloat64, math.NaN(), 0, false},
    80  		{1.000000001, -1.0, 0, false},
    81  		{-1.0, 1.000000001, 0, false},
    82  		{-1.000000001, 1.0, 0, false},
    83  		{1.0, -1.000000001, 0, false},
    84  		{10 * math.SmallestNonzeroFloat64, 10 * -math.SmallestNonzeroFloat64, 0, true},
    85  		{1e11 * math.SmallestNonzeroFloat64, 1e11 * -math.SmallestNonzeroFloat64, 0, false},
    86  		{math.SmallestNonzeroFloat64, -math.SmallestNonzeroFloat64, 0, true},
    87  		{-math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64, 0, true},
    88  		{math.SmallestNonzeroFloat64, 0, 0, true},
    89  		{0, math.SmallestNonzeroFloat64, 0, true},
    90  		{-math.SmallestNonzeroFloat64, 0, 0, true},
    91  		{0, -math.SmallestNonzeroFloat64, 0, true},
    92  		{0.000000001, -math.SmallestNonzeroFloat64, 0, false},
    93  		{0.000000001, math.SmallestNonzeroFloat64, 0, false},
    94  		{math.SmallestNonzeroFloat64, 0.000000001, 0, false},
    95  		{-math.SmallestNonzeroFloat64, 0.000000001, 0, false},
    96  	}
    97  	for _, ts := range equalityTests {
    98  		if ts.tol == 0 {
    99  			ts.tol = 1e-5
   100  		}
   101  		if equal := EqualWithinRel(ts.a, ts.b, ts.tol); equal != ts.equal {
   102  			t.Errorf("Relative equality of %g and %g with tolerance %g returned: %v. Expected: %v",
   103  				ts.a, ts.b, ts.tol, equal, ts.equal)
   104  		}
   105  	}
   106  }
   107  
   108  func TestEqualsULP(t *testing.T) {
   109  	t.Parallel()
   110  	if f := 67329.242; !EqualWithinULP(f, nextAfterN(f, math.Inf(1), 10), 10) {
   111  		t.Errorf("Equal values returned as unequal")
   112  	}
   113  	if f := 67329.242; EqualWithinULP(f, nextAfterN(f, math.Inf(1), 5), 1) {
   114  		t.Errorf("Unequal values returned as equal")
   115  	}
   116  	if f := 67329.242; EqualWithinULP(nextAfterN(f, math.Inf(1), 5), f, 1) {
   117  		t.Errorf("Unequal values returned as equal")
   118  	}
   119  	if f := nextAfterN(0, math.Inf(1), 2); !EqualWithinULP(f, nextAfterN(f, math.Inf(-1), 5), 10) {
   120  		t.Errorf("Equal values returned as unequal")
   121  	}
   122  	if !EqualWithinULP(67329.242, 67329.242, 10) {
   123  		t.Errorf("Equal float64s not returned as equal")
   124  	}
   125  	if EqualWithinULP(1, math.NaN(), 10) {
   126  		t.Errorf("NaN returned as equal")
   127  	}
   128  }
   129  
   130  func nextAfterN(x, y float64, n int) float64 {
   131  	for i := 0; i < n; i++ {
   132  		x = math.Nextafter(x, y)
   133  	}
   134  	return x
   135  }
   136  
   137  func TestNaNWith(t *testing.T) {
   138  	t.Parallel()
   139  	tests := []struct {
   140  		payload uint64
   141  		bits    uint64
   142  	}{
   143  		{0, math.Float64bits(0 / func() float64 { return 0 }())}, // Hide the division by zero from the compiler.
   144  		{1, math.Float64bits(math.NaN())},
   145  		{1954, 0x7ff80000000007a2}, // R NA.
   146  	}
   147  
   148  	for _, test := range tests {
   149  		nan := NaNWith(test.payload)
   150  		if !math.IsNaN(nan) {
   151  			t.Errorf("expected NaN value, got:%f", nan)
   152  		}
   153  
   154  		bits := math.Float64bits(nan)
   155  
   156  		// Strip sign bit.
   157  		const sign = 1 << 63
   158  		bits &^= sign
   159  		test.bits &^= sign
   160  
   161  		if bits != test.bits {
   162  			t.Errorf("expected NaN bit representation: got:%x want:%x", bits, test.bits)
   163  		}
   164  	}
   165  }
   166  
   167  func TestNaNPayload(t *testing.T) {
   168  	t.Parallel()
   169  	tests := []struct {
   170  		f       float64
   171  		payload uint64
   172  		ok      bool
   173  	}{
   174  		{0 / func() float64 { return 0 }(), 0, true}, // Hide the division by zero from the compiler.
   175  
   176  		// The following two line are written explicitly to defend against potential changes to math.Copysign.
   177  		{math.Float64frombits(math.Float64bits(math.NaN()) | (1 << 63)), 1, true},  // math.Copysign(math.NaN(), -1)
   178  		{math.Float64frombits(math.Float64bits(math.NaN()) &^ (1 << 63)), 1, true}, // math.Copysign(math.NaN(), 1)
   179  
   180  		{NaNWith(1954), 1954, true}, // R NA.
   181  
   182  		{math.Copysign(0, -1), 0, false},
   183  		{0, 0, false},
   184  		{math.Inf(-1), 0, false},
   185  		{math.Inf(1), 0, false},
   186  
   187  		{math.Float64frombits(0x7ff0000000000001), 0, false}, // Signalling NaN.
   188  	}
   189  
   190  	for _, test := range tests {
   191  		payload, ok := NaNPayload(test.f)
   192  		if payload != test.payload {
   193  			t.Errorf("expected NaN payload: got:%x want:%x", payload, test.payload)
   194  		}
   195  		if ok != test.ok {
   196  			t.Errorf("expected NaN status: got:%t want:%t", ok, test.ok)
   197  		}
   198  	}
   199  }
   200  
   201  func TestRound(t *testing.T) {
   202  	t.Parallel()
   203  	for _, test := range []struct {
   204  		x    float64
   205  		prec int
   206  		want float64
   207  	}{
   208  		{x: 0, prec: 1, want: 0},
   209  		{x: math.Inf(1), prec: 1, want: math.Inf(1)},
   210  		{x: math.Inf(-1), prec: 1, want: math.Inf(-1)},
   211  		{x: math.NaN(), prec: 1, want: math.NaN()},
   212  		{x: func() float64 { var f float64; return -f }(), prec: 1, want: 0},
   213  		{x: math.MaxFloat64 / 2, prec: 1, want: math.MaxFloat64 / 2},
   214  		{x: 1 << 64, prec: 1, want: 1 << 64},
   215  		{x: 454.4445, prec: 3, want: 454.445},
   216  		{x: 454.44445, prec: 4, want: 454.4445},
   217  		{x: 0.42499, prec: 4, want: 0.425},
   218  		{x: 0.42599, prec: 4, want: 0.426},
   219  		{x: 0.424999999999993, prec: 2, want: 0.42},
   220  		{x: 0.425, prec: 2, want: 0.43},
   221  		{x: 0.425000000000001, prec: 2, want: 0.43},
   222  		{x: 123.4244999999999, prec: 3, want: 123.424},
   223  		{x: 123.4245, prec: 3, want: 123.425},
   224  		{x: 123.4245000000001, prec: 3, want: 123.425},
   225  		{x: -0.49999999999999994, prec: 0, want: 0},
   226  		{x: 0.49999999999999994, prec: 0, want: 0},
   227  
   228  		{x: 454.45, prec: 0, want: 454},
   229  		{x: 454.45, prec: 1, want: 454.5},
   230  		{x: 454.45, prec: 2, want: 454.45},
   231  		{x: 454.45, prec: 3, want: 454.45},
   232  		{x: 454.445, prec: 0, want: 454},
   233  		{x: 454.445, prec: 1, want: 454.4},
   234  		{x: 454.445, prec: 2, want: 454.45},
   235  		{x: 454.445, prec: 3, want: 454.445},
   236  		{x: 454.445, prec: 4, want: 454.445},
   237  		{x: 454.55, prec: 0, want: 455},
   238  		{x: 454.55, prec: 1, want: 454.6},
   239  		{x: 454.55, prec: 2, want: 454.55},
   240  		{x: 454.55, prec: 3, want: 454.55},
   241  		{x: 454.455, prec: 0, want: 454},
   242  		{x: 454.455, prec: 1, want: 454.5},
   243  		{x: 454.455, prec: 2, want: 454.46},
   244  		{x: 454.455, prec: 3, want: 454.455},
   245  		{x: 454.455, prec: 4, want: 454.455},
   246  
   247  		// Negative precision.
   248  		{x: math.Inf(1), prec: -1, want: math.Inf(1)},
   249  		{x: math.Inf(-1), prec: -1, want: math.Inf(-1)},
   250  		{x: math.NaN(), prec: -1, want: math.NaN()},
   251  		{x: func() float64 { var f float64; return -f }(), prec: -1, want: 0},
   252  		{x: 454.45, prec: -1, want: 450},
   253  		{x: 454.45, prec: -2, want: 500},
   254  		{x: 500, prec: -3, want: 1000},
   255  		{x: 500, prec: -4, want: 0},
   256  		{x: 1500, prec: -3, want: 2000},
   257  		{x: 1500, prec: -4, want: 0},
   258  	} {
   259  		for _, sign := range []float64{1, -1} {
   260  			got := Round(sign*test.x, test.prec)
   261  			want := sign * test.want
   262  			if want == 0 {
   263  				want = 0
   264  			}
   265  			if (got != want || math.Signbit(got) != math.Signbit(want)) && !(math.IsNaN(got) && math.IsNaN(want)) {
   266  				t.Errorf("unexpected result for Round(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want)
   267  			}
   268  		}
   269  	}
   270  }
   271  
   272  func TestRoundEven(t *testing.T) {
   273  	t.Parallel()
   274  	for _, test := range []struct {
   275  		x    float64
   276  		prec int
   277  		want float64
   278  	}{
   279  		{x: 0, prec: 1, want: 0},
   280  		{x: math.Inf(1), prec: 1, want: math.Inf(1)},
   281  		{x: math.Inf(-1), prec: 1, want: math.Inf(-1)},
   282  		{x: math.NaN(), prec: 1, want: math.NaN()},
   283  		{x: func() float64 { var f float64; return -f }(), prec: 1, want: 0},
   284  		{x: math.MaxFloat64 / 2, prec: 1, want: math.MaxFloat64 / 2},
   285  		{x: 1 << 64, prec: 1, want: 1 << 64},
   286  		{x: 454.4445, prec: 3, want: 454.444},
   287  		{x: 454.44445, prec: 4, want: 454.4444},
   288  		{x: 0.42499, prec: 4, want: 0.425},
   289  		{x: 0.42599, prec: 4, want: 0.426},
   290  		{x: 0.424999999999993, prec: 2, want: 0.42},
   291  		{x: 0.425, prec: 2, want: 0.42},
   292  		{x: 0.425000000000001, prec: 2, want: 0.43},
   293  		{x: 123.4244999999999, prec: 3, want: 123.424},
   294  		{x: 123.4245, prec: 3, want: 123.424},
   295  		{x: 123.4245000000001, prec: 3, want: 123.425},
   296  		{x: -0.49999999999999994, prec: 0, want: 0},
   297  		{x: 0.49999999999999994, prec: 0, want: 0},
   298  
   299  		{x: 454.45, prec: 0, want: 454},
   300  		{x: 454.45, prec: 1, want: 454.4},
   301  		{x: 454.45, prec: 2, want: 454.45},
   302  		{x: 454.45, prec: 3, want: 454.45},
   303  		{x: 454.445, prec: 0, want: 454},
   304  		{x: 454.445, prec: 1, want: 454.4},
   305  		{x: 454.445, prec: 2, want: 454.44},
   306  		{x: 454.445, prec: 3, want: 454.445},
   307  		{x: 454.445, prec: 4, want: 454.445},
   308  		{x: 454.55, prec: 0, want: 455},
   309  		{x: 454.55, prec: 1, want: 454.6},
   310  		{x: 454.55, prec: 2, want: 454.55},
   311  		{x: 454.55, prec: 3, want: 454.55},
   312  		{x: 454.455, prec: 0, want: 454},
   313  		{x: 454.455, prec: 1, want: 454.5},
   314  		{x: 454.455, prec: 2, want: 454.46},
   315  		{x: 454.455, prec: 3, want: 454.455},
   316  		{x: 454.455, prec: 4, want: 454.455},
   317  
   318  		// Negative precision.
   319  		{x: math.Inf(1), prec: -1, want: math.Inf(1)},
   320  		{x: math.Inf(-1), prec: -1, want: math.Inf(-1)},
   321  		{x: math.NaN(), prec: -1, want: math.NaN()},
   322  		{x: func() float64 { var f float64; return -f }(), prec: -1, want: 0},
   323  		{x: 454.45, prec: -1, want: 450},
   324  		{x: 454.45, prec: -2, want: 500},
   325  		{x: 500, prec: -3, want: 0},
   326  		{x: 500, prec: -4, want: 0},
   327  		{x: 1500, prec: -3, want: 2000},
   328  		{x: 1500, prec: -4, want: 0},
   329  	} {
   330  		for _, sign := range []float64{1, -1} {
   331  			got := RoundEven(sign*test.x, test.prec)
   332  			want := sign * test.want
   333  			if want == 0 {
   334  				want = 0
   335  			}
   336  			if (got != want || math.Signbit(got) != math.Signbit(want)) && !(math.IsNaN(got) && math.IsNaN(want)) {
   337  				t.Errorf("unexpected result for RoundEven(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want)
   338  			}
   339  		}
   340  	}
   341  }
   342  
   343  func TestSame(t *testing.T) {
   344  	t.Parallel()
   345  	for _, test := range []struct {
   346  		a, b float64
   347  		want bool
   348  	}{
   349  		{a: 0, b: 0, want: true},
   350  		{a: 1, b: 1, want: true},
   351  		{a: -1, b: 1, want: false},
   352  		{a: 0, b: 1, want: false},
   353  		{a: 1, b: 0, want: false},
   354  		{a: -1, b: 1, want: false},
   355  		{a: math.NaN(), b: math.NaN(), want: true},
   356  		{a: 1, b: math.NaN(), want: false},
   357  		{a: math.Inf(1), b: math.NaN(), want: false},
   358  		{a: math.NaN(), b: math.Inf(1), want: false},
   359  		{a: math.NaN(), b: 1, want: false},
   360  		{a: math.Inf(1), b: math.Inf(1), want: true},
   361  		{a: math.Inf(-1), b: math.Inf(1), want: false},
   362  		{a: math.Inf(1), b: math.Inf(-1), want: false},
   363  	} {
   364  		got := Same(test.a, test.b)
   365  		if got != test.want {
   366  			t.Errorf("unexpected results for a=%f b=%f: got:%t want:%t", test.a, test.b, got, test.want)
   367  		}
   368  	}
   369  }