// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package core import ( "math" "testing" ) // TestGeneratorStreamIsPinned pins the raw stream of one seed: the // splitmix64 seeding walk and the xoshiro core must keep producing // exactly these bits, because every recorded oracle digest downstream // of the generator hangs on them. func TestGeneratorStreamIsPinned(t *testing.T) { g := NewGenerator(1) for _, want := range []uint64{ 0xcfc5d07f6f03c29b, 0xbf424132963fe08d, 0x19a37d5757aaf520, 0xbf08119f05cd56d6, } { if got := g.Next(); got != want { t.Fatalf("Next() = %#016x, want %#016x", got, want) } } n, err := Normal(NewGenerator(7), 3, 0, 1) if err != nil { t.Fatal(err) } for i, want := range []float64{1.674036445441065, 0.53789816819896552, 1.2079282540944534} { if n.FloatAt(i) != want { t.Fatalf("Normal draw %d = %.17g, want %.17g", i, n.FloatAt(i), want) } } } // TestSplitmix64 pins the scalar mixer against an independent // transcription of the finaliser and pins the state discipline: the // returned state is the input plus the golden constant, the output is // the mixed state, and chaining reproduces the walk. func TestSplitmix64(t *testing.T) { mix := func(z uint64) uint64 { z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9 z = (z ^ (z >> 27)) * 0x94D049BB133111EB return z ^ (z >> 31) } const golden = 0x9E3779B97F4A7C15 state, v := Splitmix64(0) if state != golden || v != mix(golden) { t.Fatalf("Splitmix64(0) = (%#016x, %#016x), want (%#016x, %#016x)", state, v, uint64(golden), mix(golden)) } for _, s := range []uint64{0, 1, 0xdeadbeef, ^uint64(0)} { state, v := Splitmix64(s) if state != s+golden { t.Fatalf("Splitmix64(%#016x) advanced the state to %#016x, want %#016x", s, state, s+golden) } if v != mix(state) { t.Fatalf("Splitmix64(%#016x) output %#016x, want %#016x", s, v, mix(state)) } // Chaining from the returned state repeats the definition. next, nv := Splitmix64(state) if nv != mix(next) || next != state+golden { t.Fatal("the chained step disagrees with the one-step definition") } } } // mustSub builds a substream, failing the test on a bad index. func mustSub(t *testing.T, seed int64, index int) *Generator { t.Helper() g, err := Substream(seed, index) if err != nil { t.Fatalf("Substream(%d, %d): %v", seed, index, err) } return g } // draw returns n uniform floats from g. func draw(t *testing.T, g *Generator, n int) []float64 { t.Helper() a, err := Floats(g, n) if err != nil { t.Fatal(err) } return a.RawFloats()[:n] } // sameBits reports whether two draw prefixes are bit for bit equal. func sameBits(a, b []float64) bool { if len(a) != len(b) { return false } for i := range a { if math.Float64bits(a[i]) != math.Float64bits(b[i]) { return false } } return true } // TestSubstream pins the stream family: the same seed and index // reproduce the same draws, distinct indices give distinct draws (so // no member is a copy of another), the family differs from the plain // seeded generator, and a negative index is an error. func TestSubstream(t *testing.T) { const draws = 16 base := draw(t, mustSub(t, 42, 0), draws) for i := 1; i < 8; i++ { if sameBits(draw(t, mustSub(t, 42, i), draws), base) { t.Fatalf("substream %d drew the same prefix as substream 0", i) } } // Determinism: the same index redraws the same bits. if !sameBits(draw(t, mustSub(t, 42, 3), draws), draw(t, mustSub(t, 42, 3), draws)) { t.Fatal("the same substream drew different bits on a second construction") } // The family hangs off the seed, not beside the plain generator: // substream 0 must differ from NewGenerator(42) and from the // neighbouring seed's plain stream. for _, seed := range []int64{42, 43} { if sameBits(draw(t, NewGenerator(seed), draws), base) { t.Fatalf("substream 0 coincides with NewGenerator(%d)", seed) } } // A large index is as legal as a small one. if _, err := Substream(42, 1<<40); err != nil { t.Fatalf("Substream at index 2^40: %v", err) } if _, err := Substream(42, -1); err == nil { t.Fatal("a negative index: want an error") } }