79 lines
2.2 KiB
C++
79 lines
2.2 KiB
C++
|
|
// tests/cpp/test_rng.cpp — verify deterministic seeding, range bounds, and
|
||
|
|
// reasonable statistical shape on the gaussian helper.
|
||
|
|
|
||
|
|
#include "test_helpers.hpp"
|
||
|
|
#include "../../nisps/core/rng.hpp"
|
||
|
|
|
||
|
|
NISPS_TEST(rng_deterministic_for_same_seed) {
|
||
|
|
nisps::Rng a(42ull);
|
||
|
|
nisps::Rng b(42ull);
|
||
|
|
for (int i = 0; i < 1000; ++i) {
|
||
|
|
NISPS_EXPECT(a.next_u64() == b.next_u64());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
NISPS_TEST(rng_diverges_for_different_seeds) {
|
||
|
|
nisps::Rng a(0ull);
|
||
|
|
nisps::Rng b(1ull);
|
||
|
|
int distinct = 0;
|
||
|
|
for (int i = 0; i < 100; ++i) {
|
||
|
|
if (a.next_u64() != b.next_u64()) ++distinct;
|
||
|
|
}
|
||
|
|
// Should differ in nearly every draw (probability of collision ~ 2^-64).
|
||
|
|
NISPS_EXPECT(distinct >= 99);
|
||
|
|
}
|
||
|
|
|
||
|
|
NISPS_TEST(rng_zero_seed_does_not_lock_up) {
|
||
|
|
nisps::Rng r(0ull);
|
||
|
|
// Pure xoshiro with all-zero state is degenerate; our splitmix64 fan-out
|
||
|
|
// should prevent that. Confirm we get nonzero output.
|
||
|
|
bool any_nonzero = false;
|
||
|
|
for (int i = 0; i < 16; ++i) {
|
||
|
|
if (r.next_u64() != 0ull) { any_nonzero = true; break; }
|
||
|
|
}
|
||
|
|
NISPS_EXPECT(any_nonzero);
|
||
|
|
}
|
||
|
|
|
||
|
|
NISPS_TEST(rng_uniform_in_unit_interval) {
|
||
|
|
nisps::Rng r(7ull);
|
||
|
|
for (int i = 0; i < 10000; ++i) {
|
||
|
|
const float v = r.next_float_uniform();
|
||
|
|
NISPS_EXPECT(v >= 0.f);
|
||
|
|
NISPS_EXPECT(v < 1.f);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
NISPS_TEST(rng_signed_in_minus_plus) {
|
||
|
|
nisps::Rng r(7ull);
|
||
|
|
for (int i = 0; i < 10000; ++i) {
|
||
|
|
const float v = r.next_float_signed();
|
||
|
|
NISPS_EXPECT(v >= -1.f);
|
||
|
|
NISPS_EXPECT(v < 1.f);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
NISPS_TEST(rng_uniform_mean_near_half) {
|
||
|
|
nisps::Rng r(123ull);
|
||
|
|
double sum = 0.0;
|
||
|
|
constexpr int N = 100000;
|
||
|
|
for (int i = 0; i < N; ++i) sum += r.next_float_uniform();
|
||
|
|
const double mean = sum / N;
|
||
|
|
NISPS_EXPECT_NEAR(mean, 0.5, 0.01);
|
||
|
|
}
|
||
|
|
|
||
|
|
NISPS_TEST(rng_gaussian_stddev_close_to_one) {
|
||
|
|
nisps::Rng r(99ull);
|
||
|
|
constexpr int N = 100000;
|
||
|
|
double sum = 0.0, sq = 0.0;
|
||
|
|
for (int i = 0; i < N; ++i) {
|
||
|
|
const double v = r.next_float_gaussian(1.f);
|
||
|
|
sum += v;
|
||
|
|
sq += v * v;
|
||
|
|
}
|
||
|
|
const double mean = sum / N;
|
||
|
|
const double var = sq / N - mean * mean;
|
||
|
|
NISPS_EXPECT_NEAR(mean, 0.0, 0.05);
|
||
|
|
// sum-of-three-uniforms gives variance exactly 1.0 in the limit.
|
||
|
|
NISPS_EXPECT_NEAR(var, 1.0, 0.05);
|
||
|
|
}
|