authorgravatar for 50984334+francescoalemanno@users.noreply.github.comFrancesco Alemanno <50984334+francescoalemanno@users.noreply.github.com> 2022-05-24 15:01:28+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-24 22:48:51-04:00
loga0775fdaa1e7427dcd6be9b19726d4996344e9fa
tree8318eb1bd351d390b807f0c601aacaed0f985474
parent60f0acd9b9c2bced47ba1c214460f34b73738f95

Add std.rand.RomuTrio

Co-authored-by: ominitay <37453713+ominitay@users.noreply.github.com>

2 files changed, 133 insertions(+), 0 deletions(-)

lib/std/rand.zig+1
......@@ -26,6 +26,7 @@ pub const Pcg = @import("rand/Pcg.zig");
2626pub const Xoroshiro128 = @import("rand/Xoroshiro128.zig");
2727pub const Xoshiro256 = @import("rand/Xoshiro256.zig");
2828pub const Sfc64 = @import("rand/Sfc64.zig");
29pub const RomuTrio = @import("rand/RomuTrio.zig");
2930
3031pub const Random = struct {
3132 ptr: *anyopaque,
lib/std/rand/RomuTrio.zig created+132
......@@ -0,0 +1,132 @@
1// Website: romu-random.org
2// Reference paper: http://arxiv.org/abs/2002.11331
3// Beware: this PRNG is trivially predictable. While fast, it should *never* be used for cryptographic purposes.
4
5const std = @import("std");
6const Random = std.rand.Random;
7const math = std.math;
8const RomuTrio = @This();
9
10x_state: u64,
11y_state: u64,
12z_state: u64, // set to nonzero seed
13
14pub fn init(init_s: u64) RomuTrio {
15 var x = RomuTrio{ .x_state = undefined, .y_state = undefined, .z_state = undefined };
16 x.seed(init_s);
17 return x;
18}
19
20pub fn random(self: *RomuTrio) Random {
21 return Random.init(self, fill);
22}
23
24fn next(self: *RomuTrio) u64 {
25 const xp = self.x_state;
26 const yp = self.y_state;
27 const zp = self.z_state;
28 self.x_state = 15241094284759029579 *% zp;
29 self.y_state = yp -% xp;
30 self.y_state = std.math.rotl(u64, self.y_state, 12);
31 self.z_state = zp -% yp;
32 self.z_state = std.math.rotl(u64, self.z_state, 44);
33 return xp;
34}
35
36pub fn seedWithBuf(self: *RomuTrio, buf: [24]u8) void {
37 const seed_buf = @bitCast([3]u64, buf);
38 self.x_state = seed_buf[0];
39 self.y_state = seed_buf[1];
40 self.z_state = seed_buf[2];
41}
42
43pub fn seed(self: *RomuTrio, init_s: u64) void {
44 // RomuTrio requires 192-bits of seed.
45 var gen = std.rand.SplitMix64.init(init_s);
46
47 self.x_state = gen.next();
48 self.y_state = gen.next();
49 self.z_state = gen.next();
50}
51
52pub fn fill(self: *RomuTrio, buf: []u8) void {
53 var i: usize = 0;
54 const aligned_len = buf.len - (buf.len & 7);
55
56 // Complete 8 byte segments.
57 while (i < aligned_len) : (i += 8) {
58 var n = self.next();
59 comptime var j: usize = 0;
60 inline while (j < 8) : (j += 1) {
61 buf[i + j] = @truncate(u8, n);
62 n >>= 8;
63 }
64 }
65
66 // Remaining. (cuts the stream)
67 if (i != buf.len) {
68 var n = self.next();
69 while (i < buf.len) : (i += 1) {
70 buf[i] = @truncate(u8, n);
71 n >>= 8;
72 }
73 }
74}
75
76test "RomuTrio sequence" {
77 // Unfortunately there does not seem to be an official test sequence.
78 var r = RomuTrio.init(0);
79
80 const seq = [_]u64{
81 16294208416658607535,
82 13964609475759908645,
83 4703697494102998476,
84 3425221541186733346,
85 2285772463536419399,
86 9454187757529463048,
87 13695907680080547496,
88 8328236714879408626,
89 12323357569716880909,
90 12375466223337721820,
91 };
92
93 for (seq) |s| {
94 try std.testing.expectEqual(s, r.next());
95 }
96}
97
98test "RomuTrio fill" {
99 // Unfortunately there does not seem to be an official test sequence.
100 var r = RomuTrio.init(0);
101
102 const seq = [_]u64{
103 16294208416658607535,
104 13964609475759908645,
105 4703697494102998476,
106 3425221541186733346,
107 2285772463536419399,
108 9454187757529463048,
109 13695907680080547496,
110 8328236714879408626,
111 12323357569716880909,
112 12375466223337721820,
113 };
114
115 for (seq) |s| {
116 var buf0: [8]u8 = undefined;
117 var buf1: [7]u8 = undefined;
118 std.mem.writeIntLittle(u64, &buf0, s);
119 r.fill(&buf1);
120 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
121 }
122}
123
124test "RomuTrio buf seeding test" {
125 const buf0 = @bitCast([24]u8, [3]u64{ 16294208416658607535, 13964609475759908645, 4703697494102998476 });
126 const resulting_state = .{ .x = 16294208416658607535, .y = 13964609475759908645, .z = 4703697494102998476 };
127 var r = RomuTrio.init(0);
128 r.seedWithBuf(buf0);
129 try std.testing.expect(r.x_state == resulting_state.x);
130 try std.testing.expect(r.y_state == resulting_state.y);
131 try std.testing.expect(r.z_state == resulting_state.z);
132}