| // Copyright 2022 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package benchunit | |
| import ( | |
| "math" | |
| "testing" | |
| ) | |
| func TestScale(t *testing.T) { | |
| var cls Class | |
| test := func(num float64, want, wantPred string) { | |
| t.Helper() | |
| got := Scale(num, cls) | |
| if got != want { | |
| t.Errorf("for %v, got %s, want %s", num, got, want) | |
| } | |
| // Check what happens when this number is exactly on | |
| // the crux between two scale factors. | |
| pred := math.Nextafter(num, 0) | |
| got = Scale(pred, cls) | |
| if got != wantPred { | |
| dir := "-ε" | |
| if num < 0 { | |
| dir = "+ε" | |
| } | |
| t.Errorf("for %v%s, got %s, want %s", num, dir, got, wantPred) | |
| } | |
| } | |
| cls = Decimal | |
| // Smoke tests | |
| test(0, "0.000", "0.000") | |
| test(1, "1.000", "1.000") | |
| test(-1, "-1.000", "-1.000") | |
| // Full range | |
| test(9999500000000000, "9999.5T", "9999.5T") | |
| test(999950000000000, "1000.0T", "999.9T") | |
| test(99995000000000, "100.0T", "99.99T") | |
| test(9999500000000, "10.00T", "9.999T") | |
| test(999950000000, "1.000T", "999.9G") | |
| test(99995000000, "100.0G", "99.99G") | |
| test(9999500000, "10.00G", "9.999G") | |
| test(999950000, "1.000G", "999.9M") | |
| test(99995000, "100.0M", "99.99M") | |
| test(9999500, "10.00M", "9.999M") | |
| test(999950, "1.000M", "999.9k") | |
| test(99995, "100.0k", "99.99k") | |
| test(9999.5, "10.00k", "9.999k") | |
| test(999.95, "1.000k", "999.9") | |
| test(99.995, "100.0", "99.99") | |
| test(9.9995, "10.00", "9.999") | |
| test(.99995, "1.000", "999.9m") | |
| test(.099995, "100.0m", "99.99m") | |
| test(.0099995, "10.00m", "9.999m") | |
| test(.00099995, "1.000m", "999.9µ") | |
| test(.000099995, "100.0µ", "99.99µ") | |
| test(.0000099995, "10.00µ", "9.999µ") | |
| test(.00000099995, "1.000µ", "999.9n") | |
| test(.000000099995, "100.0n", "99.99n") | |
| test(.0000000099995, "10.00n", "9.999n") | |
| test(.00000000099995, "1.000n", "0.9999n") // First pred we won't up-scale | |
| // Below the smallest scale unit rounding gets imperfect, but | |
| // it's off from the ideal by at most one ulp, so we accept it. | |
| test(math.Nextafter(.000000000099995, 1), "0.1000n", "0.09999n") | |
| test(.0000000000099995, "0.01000n", "0.009999n") | |
| test(math.Nextafter(.00000000000099995, 1), "0.001000n", "0.0009999n") | |
| test(.000000000000099995, "0.0001000n", "0.00009999n") | |
| test(.0000000000000099995, "0.00001000n", "0.000009999n") | |
| test(math.Nextafter(.00000000000000099995, 1), "0.000001000n", "0.0000009999n") | |
| // Misc | |
| test(-99995000000000, "-100.0T", "-99.99T") | |
| test(-.0000000099995, "-10.00n", "-9.999n") | |
| cls = Binary | |
| // Smoke tests | |
| test(0, "0.000", "0.000") | |
| test(1, "1.000", "1.000") | |
| test(-1, "-1.000", "-1.000") | |
| // Full range | |
| test(.99995*(1<<50), "1023.9Ti", "1023.9Ti") | |
| test(99.995*(1<<40), "100.0Ti", "99.99Ti") | |
| test(9.9995*(1<<40), "10.00Ti", "9.999Ti") | |
| test(.99995*(1<<40), "1.000Ti", "1023.9Gi") | |
| test(99.995*(1<<30), "100.0Gi", "99.99Gi") | |
| test(9.9995*(1<<30), "10.00Gi", "9.999Gi") | |
| test(.99995*(1<<30), "1.000Gi", "1023.9Mi") | |
| test(99.995*(1<<20), "100.0Mi", "99.99Mi") | |
| test(9.9995*(1<<20), "10.00Mi", "9.999Mi") | |
| test(.99995*(1<<20), "1.000Mi", "1023.9Ki") | |
| test(99.995*(1<<10), "100.0Ki", "99.99Ki") | |
| test(9.9995*(1<<10), "10.00Ki", "9.999Ki") | |
| test(.99995*(1<<10), "1.000Ki", "1023.9") | |
| test(99.995*(1<<0), "100.0", "99.99") | |
| test(9.9995*(1<<0), "10.00", "9.999") | |
| test(.99995, "1.000", "0.9999") | |
| test(.099995, "0.1000", "0.09999") | |
| test(.0099995, "0.01000", "0.009999") | |
| test(.00099995, "0.001000", "0.0009999") | |
| test(.000099995, "0.0001000", "0.00009999") | |
| test(.0000099995, "0.00001000", "0.000009999") | |
| test(.00000099995, "0.000001000", "0.0000009999") | |
| // We stop at 10 digits after the decimal. Again, rounding | |
| // gets a little weird. | |
| test(.00000009995, "0.0000001000", "0.0000000999") | |
| test(math.Nextafter(.00000000995, 1), "0.0000000100", "0.0000000099") | |
| test(.00000000095, "0.0000000010", "0.0000000009") | |
| test(.00000000005, "0.0000000001", "0.0000000000") | |
| test(.000000000009, "0.0000000000", "0.0000000000") | |
| } | |
| func TestNoOpScaler(t *testing.T) { | |
| test := func(val float64, want string) { | |
| t.Helper() | |
| got := NoOpScaler.Format(val) | |
| if got != want { | |
| t.Errorf("for %v, got %s, want %s", val, got, want) | |
| } | |
| } | |
| test(1, "1") | |
| test(123456789, "123456789") | |
| test(123.456789, "123.456789") | |
| } |