authorgravatar for 12179851+leesongun@users.noreply.github.comleesongun <12179851+leesongun@users.noreply.github.com> 2021-07-04 23:15:23+09:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-07-04 16:15:23+02:00
logda2ca447c838777f1200386490808738c1183809
tree821929b41c269bcc3e057baafee23b065a67abad
parent8a863381d11adcdcb4e0509611af93c61fc89804
signature Signed by PGP key 4AEE18F83AFDEB23

implement xoshiro256++ (#9298)

Implement xoshiro256++

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

lib/std/rand.zig+1
......@@ -32,6 +32,7 @@ pub const Isaac64 = @import("rand/Isaac64.zig");
3232pub const Gimli = @import("rand/Gimli.zig");
3333pub const Pcg = @import("rand/Pcg.zig");
3434pub const Xoroshiro128 = @import("rand/Xoroshiro128.zig");
35pub const Xoshiro256 = @import("rand/Xoshiro256.zig");
3536pub const Sfc64 = @import("rand/Sfc64.zig");
3637
3738pub const Random = struct {
lib/std/rand/Xoshiro256.zig created+150
......@@ -0,0 +1,150 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! Xoshiro256++ - http://xoroshiro.di.unimi.it/
8//!
9//! PRNG
10
11const std = @import("std");
12const Random = std.rand.Random;
13const math = std.math;
14const Xoshiro256 = @This();
15
16random: Random,
17
18s: [4]u64,
19
20pub fn init(init_s: u64) Xoshiro256 {
21 var x = Xoshiro256{
22 .random = Random{ .fillFn = fill },
23 .s = undefined,
24 };
25
26 x.seed(init_s);
27 return x;
28}
29
30fn next(self: *Xoshiro256) u64 {
31 const r = math.rotl(u64, self.s[0] +% self.s[3], 23) +% self.s[0];
32
33 const t = self.s[1] << 17;
34
35 self.s[2] ^= self.s[0];
36 self.s[3] ^= self.s[1];
37 self.s[1] ^= self.s[2];
38 self.s[0] ^= self.s[3];
39
40 self.s[2] ^= t;
41
42 self.s[3] = math.rotl(u64, self.s[3], 45);
43
44 return r;
45}
46
47// Skip 2^128 places ahead in the sequence
48fn jump(self: *Xoshiro256) void {
49 var s: u256 = 0;
50
51 var table: u256 = 0x39abdc4529b1661ca9582618e03fc9aad5a61266f0c9392c180ec6d33cfd0aba;
52
53 while (table != 0) : (table >>= 1) {
54 if (@truncate(u1, table) != 0) {
55 s ^= @bitCast(u256, self.s);
56 }
57 _ = self.next();
58 }
59
60 self.s = @bitCast([4]u64, s);
61}
62
63pub fn seed(self: *Xoshiro256, init_s: u64) void {
64 // Xoshiro requires 256-bits of seed.
65 var gen = std.rand.SplitMix64.init(init_s);
66
67 self.s[0] = gen.next();
68 self.s[1] = gen.next();
69 self.s[2] = gen.next();
70 self.s[3] = gen.next();
71}
72
73fn fill(r: *Random, buf: []u8) void {
74 const self = @fieldParentPtr(Xoshiro256, "random", r);
75
76 var i: usize = 0;
77 const aligned_len = buf.len - (buf.len & 7);
78
79 // Complete 8 byte segments.
80 while (i < aligned_len) : (i += 8) {
81 var n = self.next();
82 comptime var j: usize = 0;
83 inline while (j < 8) : (j += 1) {
84 buf[i + j] = @truncate(u8, n);
85 n >>= 8;
86 }
87 }
88
89 // Remaining. (cuts the stream)
90 if (i != buf.len) {
91 var n = self.next();
92 while (i < buf.len) : (i += 1) {
93 buf[i] = @truncate(u8, n);
94 n >>= 8;
95 }
96 }
97}
98
99test "xoroshiro sequence" {
100 var r = Xoshiro256.init(0);
101
102 const seq1 = [_]u64{
103 0x53175d61490b23df,
104 0x61da6f3dc380d507,
105 0x5c0fdf91ec9a7bfc,
106 0x02eebf8c3bbe5e1a,
107 0x7eca04ebaf4a5eea,
108 0x0543c37757f08d9a,
109 };
110
111 for (seq1) |s| {
112 try std.testing.expect(s == r.next());
113 }
114
115 r.jump();
116
117 const seq2 = [_]u64{
118 0xae1db5c5e27807be,
119 0xb584c6a7fd8709fe,
120 0xc46a0ee9330fb6e,
121 0xdc0c9606f49ed76e,
122 0x1f5bb6540f6651fb,
123 0x72fa2ca734601488,
124 };
125
126 for (seq2) |s| {
127 try std.testing.expect(s == r.next());
128 }
129}
130
131test "xoroshiro fill" {
132 var r = Xoshiro256.init(0);
133
134 const seq = [_]u64{
135 0x53175d61490b23df,
136 0x61da6f3dc380d507,
137 0x5c0fdf91ec9a7bfc,
138 0x02eebf8c3bbe5e1a,
139 0x7eca04ebaf4a5eea,
140 0x0543c37757f08d9a,
141 };
142
143 for (seq) |s| {
144 var buf0: [8]u8 = undefined;
145 var buf1: [7]u8 = undefined;
146 std.mem.writeIntLittle(u64, &buf0, s);
147 Xoshiro256.fill(&r.random, &buf1);
148 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
149 }
150}