gonum.org/v1/gonum@v0.14.0/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 }