std/random/_pcg32_test.ts

123 lines
4.2 KiB
TypeScript
Raw Normal View History

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "../assert/equals.ts";
import { fromSeed, nextU32, seedFromU64 } from "./_pcg32.ts";
Deno.test("seedFromU64() generates seeds from bigints", async (t) => {
await t.step("first 10 16-bit seeds are same as rand crate", async (t) => {
/**
* Expected results obtained by copying the Rust code from
* https://github.com/rust-random/rand/blob/f7bbccaedf6c63b02855b90b003c9b1a4d1fd1cb/rand_core/src/lib.rs#L359-L388
* but directly returning `seed` instead of `Self::from_seed(seed)`
*/
// deno-fmt-ignore
const expectedResults = [
[236, 242, 115, 249, 129, 181, 205, 69, 135, 240, 70, 115, 6, 173, 108, 173],
[234, 216, 29, 114, 93, 38, 16, 78, 137, 156, 59, 248, 66, 206, 120, 46],
[77, 209, 16, 204, 177, 124, 55, 30, 237, 239, 68, 142, 238, 125, 215, 7],
[108, 90, 247, 27, 160, 186, 6, 71, 76, 124, 221, 142, 87, 133, 92, 175],
[197, 166, 196, 87, 44, 68, 69, 62, 55, 32, 34, 218, 130, 107, 171, 170],
[60, 64, 172, 11, 74, 188, 224, 128, 161, 112, 220, 75, 85, 212, 145, 251],
[177, 93, 150, 16, 48, 3, 23, 51, 155, 104, 76, 121, 82, 134, 239, 107],
[200, 12, 64, 59, 208, 32, 108, 9, 55, 166, 59, 111, 242, 79, 37, 30],
[222, 11, 88, 159, 202, 89, 63, 215, 36, 57, 0, 156, 63, 131, 114, 90],
[21, 119, 90, 241, 241, 191, 180, 229, 150, 199, 126, 251, 25, 141, 7, 4],
];
for (const [i, expected] of expectedResults.entries()) {
await t.step(`With seed ${i}n`, () => {
const actual = Array.from(seedFromU64(BigInt(i), 16));
assertEquals(actual, expected);
});
}
});
await t.step(
"generates arbitrary-length seed data from a single bigint",
async (t) => {
// deno-fmt-ignore
const expectedBytes = [234, 216, 29, 114, 93, 38, 16, 78, 137, 156, 59, 248, 66, 206, 120, 46, 186];
for (const i of expectedBytes.keys()) {
const slice = expectedBytes.slice(0, i + 1);
await t.step(`With length ${i + 1}`, () => {
const actual = Array.from(seedFromU64(1n, i + 1));
assertEquals(actual, slice);
});
}
},
);
const U64_CEIL = 2n ** 64n;
await t.step("wraps bigint input to u64", async (t) => {
await t.step("exact multiple of U64_CEIL", () => {
const expected = Array.from(seedFromU64(BigInt(0n), 16));
const actual = Array.from(seedFromU64(U64_CEIL * 99n, 16));
assertEquals(actual, expected);
});
await t.step("multiple of U64_CEIL + 1", () => {
const expected = Array.from(seedFromU64(1n, 16));
const actual = Array.from(seedFromU64(1n + U64_CEIL * 3n, 16));
assertEquals(actual, expected);
});
await t.step("multiple of U64_CEIL - 1", () => {
const expected = Array.from(seedFromU64(-1n, 16));
const actual = Array.from(seedFromU64(U64_CEIL - 1n, 16));
assertEquals(actual, expected);
});
await t.step("negative multiple of U64_CEIL", () => {
const expected = Array.from(seedFromU64(0n, 16));
const actual = Array.from(seedFromU64(U64_CEIL * -3n, 16));
assertEquals(actual, expected);
});
await t.step("negative multiple of U64_CEIL", () => {
const expected = Array.from(seedFromU64(0n, 16));
const actual = Array.from(seedFromU64(U64_CEIL * -3n, 16));
assertEquals(actual, expected);
});
});
});
Deno.test("nextU32() generates random 32-bit integers", async (t) => {
/**
* Expected results obtained from the Rust `rand` crate as follows:
* ```rs
* use rand_pcg::rand_core::{RngCore, SeedableRng};
* use rand_pcg::Lcg64Xsh32;
*
* let mut rng = Lcg64Xsh32::seed_from_u64(0);
* for _ in 0..10 {
* println!("{}", rng.next_u32());
* }
* ```
*/
const expectedResults = [
298703107,
4236525527,
336081875,
1056616254,
1060453275,
1616833669,
501767310,
2864049166,
56572352,
2362354238,
];
const pgc = fromSeed(seedFromU64(0n, 16));
const next = () => nextU32(pgc);
for (const [i, expected] of expectedResults.entries()) {
await t.step(`#${i + 1} generated uint32`, () => {
const actual = next();
assertEquals(actual, expected);
});
}
});