From 5b93212f43cb7108a354f687cfdeab6469defe9c Mon Sep 17 00:00:00 2001 From: Laura Kirsch <52753282+laura240406@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:14:56 +0100 Subject: [PATCH] Added Xorshiro128++ random number generator. (#2846) * Added Xorshiro128++ random number generator. * Fixes to xorshiro implementation + tests. --------- Co-authored-by: Christoffer Lerno --- lib/std/math/random/math.xorshiro.c3 | 42 ++++++++++++++++++++++++ releasenotes.md | 1 + test/unit/stdlib/math/random_xorshiro.c3 | 15 +++++++++ 3 files changed, 58 insertions(+) create mode 100644 lib/std/math/random/math.xorshiro.c3 create mode 100644 test/unit/stdlib/math/random_xorshiro.c3 diff --git a/lib/std/math/random/math.xorshiro.c3 b/lib/std/math/random/math.xorshiro.c3 new file mode 100644 index 000000000..f553a55af --- /dev/null +++ b/lib/std/math/random/math.xorshiro.c3 @@ -0,0 +1,42 @@ +module std::math::random; + +struct Xorshiro128PPRandom (Random) +{ + uint[4] state; +} + +<* + @require seed.len > 0 +*> +fn void Xorshiro128PPRandom.set_seed(&self, char[] seed) @dynamic +{ + self.state = random::make_seed(uint[4], seed); +} + +// Xorshiro128++ implementation +fn uint Xorshiro128PPRandom.next_int(&self) @dynamic +{ + uint result = (self.state[0] + self.state[3]).rotl(7) + self.state[0]; + + uint t = self.state[1] << 9U; + + self.state[2] ^= self.state[0]; + self.state[3] ^= self.state[1]; + self.state[1] ^= self.state[2]; + self.state[0] ^= self.state[3]; + + self.state[2] ^= t; + + self.state[3] = self.state[3].rotl(11); + + return result; +} + +<* + @require bytes.len > 0 +*> +fn void Xorshiro128PPRandom.next_bytes(&self, char[] bytes) @dynamic => @random_value_to_bytes(self.next_int, bytes); +fn uint128 Xorshiro128PPRandom.next_int128(&self) @dynamic => @long_to_int128(self.next_long()); +fn ulong Xorshiro128PPRandom.next_long(&self) @dynamic => @int_to_long(self.next_int()); +fn ushort Xorshiro128PPRandom.next_short(&self) @dynamic => (ushort)self.next_int(); +fn char Xorshiro128PPRandom.next_byte(&self) @dynamic => (char)self.next_int(); diff --git a/releasenotes.md b/releasenotes.md index c2786c6c4..46c8f1ff7 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -15,6 +15,7 @@ - Added PEM encoding/decoding. #2858 - Add Murmur3 hash. - Add optional line-length limitations to `io::readline` and `io::readline_to_stream`. #2879 +- Add Xorshiro128++. ### Fixes - Add error message if directory with output file name already exists diff --git a/test/unit/stdlib/math/random_xorshiro.c3 b/test/unit/stdlib/math/random_xorshiro.c3 new file mode 100644 index 000000000..96ccd3a3f --- /dev/null +++ b/test/unit/stdlib/math/random_xorshiro.c3 @@ -0,0 +1,15 @@ +module xorshiro_test; +import std::math; + +fn void test_vectors_xorshiro() @test +{ + Xorshiro128PPRandom a = { { 0x1, 0x2, 0x3, 0x4 } }; + test::eq(0x281, a.next_int()); + test::eq(0x180387, a.next_int()); + test::eq(0xc0183387, a.next_int()); + + a = { { ~0x1, ~0x2, ~0x3, ~0x4 } }; + test::eq(0xfffffcfd, a.next_int()); + test::eq(0x17fbf8, a.next_int()); + test::eq(0x40183386, a.next_int()); +} \ No newline at end of file