aminal/vendor/github.com/go-gl/mathgl/mgl32/util_test.go

309 lines
7.8 KiB
Go

// Copyright 2014 The go-gl 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 mgl32
import (
"math/rand"
"testing"
"time"
)
func TestEqual(t *testing.T) {
t.Parallel()
var a float32 = 1.5
var b float32 = 1.0 + .5
if !FloatEqual(a, a) {
t.Errorf("Float Equal fails on comparing a number with itself")
}
if !FloatEqual(a, b) {
t.Errorf("Float Equal fails to compare two equivalent numbers with minimal drift")
} else if !FloatEqual(b, a) {
t.Errorf("Float Equal is not symmetric for some reason")
}
if !FloatEqual(0.0, 0.0) {
t.Errorf("Float Equal fails to compare zero values correctly")
}
if FloatEqual(1.5, 1.51) {
t.Errorf("Float Equal gives false positive on large difference")
}
if FloatEqual(1.5, 1.5000001) {
t.Errorf("Float Equal gives false positive on small difference")
}
if FloatEqual(1.5, 0.0) {
t.Errorf("Float Equal gives false positive comparing with zero")
}
}
func TestEqualThreshold(t *testing.T) {
t.Parallel()
// |1.0 - 1.01| < .1
if !FloatEqualThreshold(1.0, 1.01, 1e-1) {
t.Errorf("Thresholded equal returns negative on threshold")
}
// Comes out to |1.0 - 1.01| < .0001
if FloatEqualThreshold(1.0, 1.01, 1e-3) {
t.Errorf("Thresholded equal returns false positive on tolerant threshold")
}
}
func TestEqualThresholdTable(t *testing.T) {
// http://floating-point-gui.de/errors/NearlyEqualsTest.java
tests := []struct {
A, B, Ep float32
Expected bool
}{
{1.0, 1.01, 1e-1, true},
{1.0, 1.01, 1e-3, false},
// Regular large numbers
{1000000.0, 1000001.0, 0.00001, true},
{1000001.0, 1000000.0, 0.00001, true},
{10000.0, 10001.0, 0.00001, false},
{10001.0, 10000.0, 0.00001, false},
// Negative large numbers
{-1000000.0, -1000001.0, 0.00001, true},
{-1000001.0, -1000000.0, 0.00001, true},
{-10000.0, -10001.0, 0.00001, false},
{-10001.0, -10000.0, 0.00001, false},
// Numbers around 1
{1.0000001, 1.0000002, 0.00001, true},
{1.0000002, 1.0000001, 0.00001, true},
{1.0002, 1.0001, 0.00001, false},
{1.0001, 1.0002, 0.00001, false},
// Numbers around -1
{-1.000001, -1.000002, 0.00001, true},
{-1.000002, -1.000001, 0.00001, true},
{-1.0001, -1.0002, 0.00001, false},
{-1.0002, -1.0001, 0.00001, false},
// Numbers between 1 and 0
{0.000000001000001, 0.000000001000002, 0.00001, true},
{0.000000001000002, 0.000000001000001, 0.00001, true},
{0.000000000001002, 0.000000000001001, 0.00001, false},
{0.000000000001001, 0.000000000001002, 0.00001, false},
// Numbers between -1 and 0
{-0.000000001000001, -0.000000001000002, 0.00001, true},
{-0.000000001000002, -0.000000001000001, 0.00001, true},
{-0.000000000001002, -0.000000000001001, 0.00001, false},
{-0.000000000001001, -0.000000000001002, 0.00001, false},
// Comparisons involving zero
{0.0, 0.0, 0.00001, true},
{0.0, -0.0, 0.00001, true},
{-0.0, -0.0, 0.00001, true},
{0.00000001, 0.0, 0.00001, false},
{0.0, 0.00000001, 0.00001, false},
{-0.00000001, 0.0, 0.00001, false},
{0.0, -0.00000001, 0.00001, false},
// Comparisons involving infinities
{InfPos, InfPos, 0.00001, true},
{InfNeg, InfNeg, 0.00001, true},
{InfNeg, InfPos, 0.00001, false},
{InfPos, MaxValue, 0.00001, false},
{InfNeg, -MaxValue, 0.00001, false},
// Comparisons involving NaN values
{NaN, NaN, 0.00001, false},
{0.0, NaN, 0.00001, false},
{NaN, 0.0, 0.00001, false},
{-0.0, NaN, 0.00001, false},
{NaN, -0.0, 0.00001, false},
{NaN, InfPos, 0.00001, false},
{InfPos, NaN, 0.00001, false},
{NaN, InfNeg, 0.00001, false},
{InfNeg, NaN, 0.00001, false},
{NaN, MaxValue, 0.00001, false},
{MaxValue, NaN, 0.00001, false},
{NaN, -MaxValue, 0.00001, false},
{-MaxValue, NaN, 0.00001, false},
{NaN, MinValue, 0.00001, false},
{MinValue, NaN, 0.00001, false},
{NaN, -MinValue, 0.00001, false},
{-MinValue, NaN, 0.00001, false},
// Comparisons of numbers on opposite sides of 0
{1.000000001, -1.0, 0.00001, false},
{-1.0, 1.000000001, 0.00001, false},
{-1.000000001, 1.0, 0.00001, false},
{1.0, -1.000000001, 0.00001, false},
{10 * MinValue, 10 * -MinValue, 0.00001, true},
{10000 * MinValue, 10000 * -MinValue, 0.00001, true},
// Comparisons of numbers very close to zero
{MinValue, -MinValue, 0.00001, true},
{-MinValue, MinValue, 0.00001, true},
{MinValue, 0, 0.00001, true},
{0, MinValue, 0.00001, true},
{-MinValue, 0, 0.00001, true},
{0, -MinValue, 0.00001, true},
{0.000000001, -MinValue, 0.00001, false},
{0.000000001, MinValue, 0.00001, false},
{MinValue, 0.000000001, 0.00001, false},
{-MinValue, 0.000000001, 0.00001, false},
}
for _, c := range tests {
if r := FloatEqualThreshold(c.A, c.B, c.Ep); r != c.Expected {
t.Errorf("FloatEqualThreshold(%v, %v, %v) != %v (got %v)", c.A, c.B, c.Ep, c.Expected, r)
}
}
}
func TestEqual32(t *testing.T) {
t.Parallel()
a := float32(1.5)
b := float32(1.0 + .5)
if !FloatEqual(a, a) {
t.Errorf("Float Equal fails on comparing a number with itself")
}
if !FloatEqual(a, b) {
t.Errorf("Float Equal fails to compare two equivalent numbers with minimal drift")
} else if !FloatEqual(b, a) {
t.Errorf("Float Equal is not symmetric for some reason")
}
if !FloatEqual(0.0, 0.0) {
t.Errorf("Float Equal fails to compare zero values correctly")
}
if FloatEqual(1.5, 1.51) {
t.Errorf("Float Equal gives false positive on large difference")
}
if FloatEqual(1.5, 0.0) {
t.Errorf("Float Equal gives false positive comparing with zero")
}
}
func TestClampf(t *testing.T) {
t.Parallel()
if !FloatEqual(Clamp(-1.0, 0.0, 1.0), 0.0) {
t.Errorf("Clamp returns incorrect value for below threshold")
}
if !FloatEqual(Clamp(0.0, 0.0, 1.0), 0.0) {
t.Errorf("Clamp does something weird when value is at threshold")
}
if !FloatEqual(Clamp(.14, 0.0, 1.0), .14) {
t.Errorf("Clamp fails to return correct value when value is within threshold")
}
if !FloatEqual(Clamp(1.1, 0.0, 1.0), 1.0) {
t.Errorf("Clamp fails to return max threshold when appropriate")
}
}
func TestIsClamped(t *testing.T) {
t.Parallel()
if IsClamped(-1.0, 0.0, 1.0) {
t.Errorf("Test below min is considered clamped")
}
if !IsClamped(.15, 0.0, 1.0) {
t.Errorf("Test in threshold returns false")
}
if IsClamped(1.5, 0.0, 1.0) {
t.Errorf("Test above max threshold returns false positive")
}
}
/* These benchmarks probably aren't very interesting, there's not really many ways to optimize the functions they're benchmarking */
func BenchmarkEqual(b *testing.B) {
b.StopTimer()
r := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
for i := 0; i < b.N; i++ {
b.StopTimer()
f1 := r.Float32()
f2 := r.Float32()
b.StartTimer()
FloatEqual(f1, f2)
}
}
// Here just to get a baseline of how much worse the safer equal is
func BenchmarkBuiltinEqual(b *testing.B) {
b.StopTimer()
r := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
for i := 0; i < b.N; i++ {
b.StopTimer()
f1 := r.Float32()
f2 := r.Float32()
b.StartTimer()
_ = f1 == f2
}
}
func BenchmarkClampf(b *testing.B) {
b.StopTimer()
r := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
for i := 0; i < b.N; i++ {
b.StopTimer()
a := r.Float32()
t1 := r.Float32()
t2 := r.Float32()
b.StartTimer()
Clamp(a, t1, t2)
}
}
func TestRound(t *testing.T) {
tests := []struct {
Value float32
Precision int
Expected float32
}{
{0.5, 0, 1},
{0.123, 2, 0.12},
{9.99999999, 6, 10},
{-9.99999999, 6, -10},
{-0.000099, 4, -0.0001},
}
for _, c := range tests {
if r := Round(c.Value, c.Precision); r != c.Expected {
t.Errorf("Round(%v, %v) != %v (got %v)", c.Value, c.Precision, c.Expected, r)
}
}
}
func BenchmarkRound(b *testing.B) {
b.StopTimer()
r := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
for i := 0; i < b.N; i++ {
b.StopTimer()
v := r.Float32()
p := r.Intn(10)
b.StartTimer()
Round(v, p)
}
}