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
5package scalar
6
7import (
8	"math"
9	"testing"
10)
11
12func 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
108func 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
130func 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
137func 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
167func 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
201func 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
226		{x: 454.45, prec: 0, want: 454},
227		{x: 454.45, prec: 1, want: 454.5},
228		{x: 454.45, prec: 2, want: 454.45},
229		{x: 454.45, prec: 3, want: 454.45},
230		{x: 454.445, prec: 0, want: 454},
231		{x: 454.445, prec: 1, want: 454.4},
232		{x: 454.445, prec: 2, want: 454.45},
233		{x: 454.445, prec: 3, want: 454.445},
234		{x: 454.445, prec: 4, want: 454.445},
235		{x: 454.55, prec: 0, want: 455},
236		{x: 454.55, prec: 1, want: 454.6},
237		{x: 454.55, prec: 2, want: 454.55},
238		{x: 454.55, prec: 3, want: 454.55},
239		{x: 454.455, prec: 0, want: 454},
240		{x: 454.455, prec: 1, want: 454.5},
241		{x: 454.455, prec: 2, want: 454.46},
242		{x: 454.455, prec: 3, want: 454.455},
243		{x: 454.455, prec: 4, want: 454.455},
244
245		// Negative precision.
246		{x: math.Inf(1), prec: -1, want: math.Inf(1)},
247		{x: math.Inf(-1), prec: -1, want: math.Inf(-1)},
248		{x: math.NaN(), prec: -1, want: math.NaN()},
249		{x: func() float64 { var f float64; return -f }(), prec: -1, want: 0},
250		{x: 454.45, prec: -1, want: 450},
251		{x: 454.45, prec: -2, want: 500},
252		{x: 500, prec: -3, want: 1000},
253		{x: 500, prec: -4, want: 0},
254		{x: 1500, prec: -3, want: 2000},
255		{x: 1500, prec: -4, want: 0},
256	} {
257		for _, sign := range []float64{1, -1} {
258			got := Round(sign*test.x, test.prec)
259			want := sign * test.want
260			if want == 0 {
261				want = 0
262			}
263			if (got != want || math.Signbit(got) != math.Signbit(want)) && !(math.IsNaN(got) && math.IsNaN(want)) {
264				t.Errorf("unexpected result for Round(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want)
265			}
266		}
267	}
268}
269
270func TestRoundEven(t *testing.T) {
271	t.Parallel()
272	for _, test := range []struct {
273		x    float64
274		prec int
275		want float64
276	}{
277		{x: 0, prec: 1, want: 0},
278		{x: math.Inf(1), prec: 1, want: math.Inf(1)},
279		{x: math.Inf(-1), prec: 1, want: math.Inf(-1)},
280		{x: math.NaN(), prec: 1, want: math.NaN()},
281		{x: func() float64 { var f float64; return -f }(), prec: 1, want: 0},
282		{x: math.MaxFloat64 / 2, prec: 1, want: math.MaxFloat64 / 2},
283		{x: 1 << 64, prec: 1, want: 1 << 64},
284		{x: 454.4445, prec: 3, want: 454.444},
285		{x: 454.44445, prec: 4, want: 454.4444},
286		{x: 0.42499, prec: 4, want: 0.425},
287		{x: 0.42599, prec: 4, want: 0.426},
288		{x: 0.424999999999993, prec: 2, want: 0.42},
289		{x: 0.425, prec: 2, want: 0.42},
290		{x: 0.425000000000001, prec: 2, want: 0.43},
291		{x: 123.4244999999999, prec: 3, want: 123.424},
292		{x: 123.4245, prec: 3, want: 123.424},
293		{x: 123.4245000000001, prec: 3, want: 123.425},
294
295		{x: 454.45, prec: 0, want: 454},
296		{x: 454.45, prec: 1, want: 454.4},
297		{x: 454.45, prec: 2, want: 454.45},
298		{x: 454.45, prec: 3, want: 454.45},
299		{x: 454.445, prec: 0, want: 454},
300		{x: 454.445, prec: 1, want: 454.4},
301		{x: 454.445, prec: 2, want: 454.44},
302		{x: 454.445, prec: 3, want: 454.445},
303		{x: 454.445, prec: 4, want: 454.445},
304		{x: 454.55, prec: 0, want: 455},
305		{x: 454.55, prec: 1, want: 454.6},
306		{x: 454.55, prec: 2, want: 454.55},
307		{x: 454.55, prec: 3, want: 454.55},
308		{x: 454.455, prec: 0, want: 454},
309		{x: 454.455, prec: 1, want: 454.5},
310		{x: 454.455, prec: 2, want: 454.46},
311		{x: 454.455, prec: 3, want: 454.455},
312		{x: 454.455, prec: 4, want: 454.455},
313
314		// Negative precision.
315		{x: math.Inf(1), prec: -1, want: math.Inf(1)},
316		{x: math.Inf(-1), prec: -1, want: math.Inf(-1)},
317		{x: math.NaN(), prec: -1, want: math.NaN()},
318		{x: func() float64 { var f float64; return -f }(), prec: -1, want: 0},
319		{x: 454.45, prec: -1, want: 450},
320		{x: 454.45, prec: -2, want: 500},
321		{x: 500, prec: -3, want: 0},
322		{x: 500, prec: -4, want: 0},
323		{x: 1500, prec: -3, want: 2000},
324		{x: 1500, prec: -4, want: 0},
325	} {
326		for _, sign := range []float64{1, -1} {
327			got := RoundEven(sign*test.x, test.prec)
328			want := sign * test.want
329			if want == 0 {
330				want = 0
331			}
332			if (got != want || math.Signbit(got) != math.Signbit(want)) && !(math.IsNaN(got) && math.IsNaN(want)) {
333				t.Errorf("unexpected result for RoundEven(%g, %d): got: %g, want: %g", sign*test.x, test.prec, got, want)
334			}
335		}
336	}
337}
338
339func TestSame(t *testing.T) {
340	t.Parallel()
341	for _, test := range []struct {
342		a, b float64
343		want bool
344	}{
345		{a: 0, b: 0, want: true},
346		{a: 1, b: 1, want: true},
347		{a: -1, b: 1, want: false},
348		{a: 0, b: 1, want: false},
349		{a: 1, b: 0, want: false},
350		{a: -1, b: 1, want: false},
351		{a: math.NaN(), b: math.NaN(), want: true},
352		{a: 1, b: math.NaN(), want: false},
353		{a: math.Inf(1), b: math.NaN(), want: false},
354		{a: math.NaN(), b: math.Inf(1), want: false},
355		{a: math.NaN(), b: 1, want: false},
356		{a: math.Inf(1), b: math.Inf(1), want: true},
357		{a: math.Inf(-1), b: math.Inf(1), want: false},
358		{a: math.Inf(1), b: math.Inf(-1), want: false},
359	} {
360		got := Same(test.a, test.b)
361		if got != test.want {
362			t.Errorf("unexpected results for a=%f b=%f: got:%t want:%t", test.a, test.b, got, test.want)
363		}
364	}
365}
366