Files
Halcyon/fixed/fixed_test.go
T
2026-09-19 20:21:47 +02:00

79 lines
2.2 KiB
Go

package fixed
import (
"math"
"math/rand"
"testing"
)
func near(t *testing.T, name string, got F, want, tol float64) {
t.Helper()
if d := math.Abs(got.Float64() - want); d > tol {
t.Errorf("%s: got %v want %v (diff %g)", name, got.Float64(), want, d)
}
}
func TestMulDiv(t *testing.T) {
near(t, "mul", FromInt(3).Mul(FromRatio(1, 2)), 1.5, 1e-9)
near(t, "mulneg", FromInt(-3).Mul(FromRatio(1, 2)), -1.5, 1e-9)
near(t, "div", FromInt(1).Div(FromInt(3)), 1.0/3, 1e-9)
near(t, "divneg", FromInt(-7).Div(FromInt(2)), -3.5, 1e-9)
if FromInt(1<<30).Mul(FromInt(1<<30)) != Max {
t.Error("expected saturation")
}
if FromInt(1).Div(0) != Max || FromInt(-1).Div(0) != Min {
t.Error("div by zero should saturate")
}
}
func TestSqrt(t *testing.T) {
for _, v := range []float64{0.25, 1, 2, 3, 100, 1e6, 2e9} {
f := F(v * float64(One))
near(t, "sqrt", f.Sqrt(), math.Sqrt(v), 1e-8)
}
if IntSqrt(1<<62) != 1<<31 || IntSqrt(99) != 9 {
t.Error("IntSqrt")
}
}
func TestSinCos(t *testing.T) {
r := rand.New(rand.NewSource(1))
for i := 0; i < 2000; i++ {
a := (r.Float64() - 0.5) * 40
f := F(a * float64(One))
s, c := SinCos(f)
af := f.Float64()
near(t, "sin", s, math.Sin(af), 2e-9)
near(t, "cos", c, math.Cos(af), 2e-9)
}
}
func TestAtan2(t *testing.T) {
r := rand.New(rand.NewSource(2))
for i := 0; i < 2000; i++ {
x, y := (r.Float64()-0.5)*1e6, (r.Float64()-0.5)*1e6
got := Atan2(F(y*float64(One)), F(x*float64(One)))
near(t, "atan2", got, math.Atan2(y, x), 2e-8)
}
near(t, "atan2(0,-1)", Atan2(0, -One), math.Pi, 1e-8)
}
func TestVec3(t *testing.T) {
// A 3-4-12 vector has length 13; scale it far past what a naive x*x would allow.
v := Vec{FromInt(3_000_000), FromInt(4_000_000), FromInt(12_000_000)}
near(t, "norm3", v.Len(), 13_000_000, 1e-6)
u := Vec{FromInt(3), FromInt(4), FromInt(12)}.Unit()
near(t, "unit", u.Len(), 1, 1e-8)
d := FromSpherical(FromRatio(1, 2), FromRatio(3, 10))
near(t, "spherical len", d.Len(), 1, 1e-8)
near(t, "spherical z", d.Z, math.Sin(0.3), 1e-8)
near(t, "spherical x", d.X, math.Cos(0.3)*math.Cos(0.5), 1e-8)
r := Vec{One, 0, 0}.RotateX(HalfPi).RotateZ(HalfPi)
near(t, "rot x", r.X, 0, 1e-8)
near(t, "rot y", r.Y, 1, 1e-8)
r = Vec{0, One, 0}.RotateX(HalfPi)
near(t, "rotx z", r.Z, 1, 1e-8)
}