authorgravatar for 37453713+Ominitay@users.noreply.github.comOminitay <37453713+Ominitay@users.noreply.github.com> 2021-10-27 15:53:29+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-27 16:07:48-04:00
logc1a5ff34f3f68a2a0bc32828ab483328cd436fea
treebad85387a89da38890f72696ccfc0ae3c416ab0f
parent9024f27d8f5cb651e2260348ce0ee6fd67fc2c32

std.rand: Refactor `Random` interface

These changes have been made to resolve issue #10037. The `Random` interface was implemented in such a way that causes significant slowdown when calling the `fill` function of the rng used. The `Random` interface is no longer stored in a field of the rng, and is instead returned by the child function `random()` of the rng. This avoids the performance issues caused by the interface.

18 files changed, 291 insertions(+), 244 deletions(-)

lib/std/atomic/queue.zig+3-2
...@@ -242,10 +242,11 @@ test "std.atomic.Queue" {...@@ -242,10 +242,11 @@ test "std.atomic.Queue" {
242242
243fn startPuts(ctx: *Context) u8 {243fn startPuts(ctx: *Context) u8 {
244 var put_count: usize = puts_per_thread;244 var put_count: usize = puts_per_thread;
245 var r = std.rand.DefaultPrng.init(0xdeadbeef);245 var prng = std.rand.DefaultPrng.init(0xdeadbeef);
246 const random = prng.random();
246 while (put_count != 0) : (put_count -= 1) {247 while (put_count != 0) : (put_count -= 1) {
247 std.time.sleep(1); // let the os scheduler be our fuzz248 std.time.sleep(1); // let the os scheduler be our fuzz
248 const x = @bitCast(i32, r.random.int(u32));249 const x = @bitCast(i32, random.int(u32));
249 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;250 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
250 node.* = .{251 node.* = .{
251 .prev = undefined,252 .prev = undefined,
lib/std/atomic/stack.zig+3-2
...@@ -147,10 +147,11 @@ test "std.atomic.stack" {...@@ -147,10 +147,11 @@ test "std.atomic.stack" {
147147
148fn startPuts(ctx: *Context) u8 {148fn startPuts(ctx: *Context) u8 {
149 var put_count: usize = puts_per_thread;149 var put_count: usize = puts_per_thread;
150 var r = std.rand.DefaultPrng.init(0xdeadbeef);150 var prng = std.rand.DefaultPrng.init(0xdeadbeef);
151 const random = prng.random();
151 while (put_count != 0) : (put_count -= 1) {152 while (put_count != 0) : (put_count -= 1) {
152 std.time.sleep(1); // let the os scheduler be our fuzz153 std.time.sleep(1); // let the os scheduler be our fuzz
153 const x = @bitCast(i32, r.random.int(u32));154 const x = @bitCast(i32, random.int(u32));
154 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;155 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
155 node.* = Stack(i32).Node{156 node.* = Stack(i32).Node{
156 .next = undefined,157 .next = undefined,
lib/std/crypto/benchmark.zig+11-10
...@@ -11,6 +11,7 @@ const KiB = 1024;...@@ -11,6 +11,7 @@ const KiB = 1024;
11const MiB = 1024 * KiB;11const MiB = 1024 * KiB;
1212
13var prng = std.rand.DefaultPrng.init(0);13var prng = std.rand.DefaultPrng.init(0);
14const random = prng.random();
1415
15const Crypto = struct {16const Crypto = struct {
16 ty: type,17 ty: type,
...@@ -34,7 +35,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64...@@ -34,7 +35,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
34 var h = Hash.init(.{});35 var h = Hash.init(.{});
3536
36 var block: [Hash.digest_length]u8 = undefined;37 var block: [Hash.digest_length]u8 = undefined;
37 prng.random.bytes(block[0..]);38 random.bytes(block[0..]);
3839
39 var offset: usize = 0;40 var offset: usize = 0;
40 var timer = try Timer.start();41 var timer = try Timer.start();
...@@ -66,11 +67,11 @@ const macs = [_]Crypto{...@@ -66,11 +67,11 @@ const macs = [_]Crypto{
6667
67pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {68pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
68 var in: [512 * KiB]u8 = undefined;69 var in: [512 * KiB]u8 = undefined;
69 prng.random.bytes(in[0..]);70 random.bytes(in[0..]);
7071
71 const key_length = if (Mac.key_length == 0) 32 else Mac.key_length;72 const key_length = if (Mac.key_length == 0) 32 else Mac.key_length;
72 var key: [key_length]u8 = undefined;73 var key: [key_length]u8 = undefined;
73 prng.random.bytes(key[0..]);74 random.bytes(key[0..]);
7475
75 var mac: [Mac.mac_length]u8 = undefined;76 var mac: [Mac.mac_length]u8 = undefined;
76 var offset: usize = 0;77 var offset: usize = 0;
...@@ -94,10 +95,10 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c...@@ -94,10 +95,10 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
94 std.debug.assert(DhKeyExchange.shared_length >= DhKeyExchange.secret_length);95 std.debug.assert(DhKeyExchange.shared_length >= DhKeyExchange.secret_length);
9596
96 var secret: [DhKeyExchange.shared_length]u8 = undefined;97 var secret: [DhKeyExchange.shared_length]u8 = undefined;
97 prng.random.bytes(secret[0..]);98 random.bytes(secret[0..]);
9899
99 var public: [DhKeyExchange.shared_length]u8 = undefined;100 var public: [DhKeyExchange.shared_length]u8 = undefined;
100 prng.random.bytes(public[0..]);101 random.bytes(public[0..]);
101102
102 var timer = try Timer.start();103 var timer = try Timer.start();
103 const start = timer.lap();104 const start = timer.lap();
...@@ -211,15 +212,15 @@ const aeads = [_]Crypto{...@@ -211,15 +212,15 @@ const aeads = [_]Crypto{
211212
212pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {213pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {
213 var in: [512 * KiB]u8 = undefined;214 var in: [512 * KiB]u8 = undefined;
214 prng.random.bytes(in[0..]);215 random.bytes(in[0..]);
215216
216 var tag: [Aead.tag_length]u8 = undefined;217 var tag: [Aead.tag_length]u8 = undefined;
217218
218 var key: [Aead.key_length]u8 = undefined;219 var key: [Aead.key_length]u8 = undefined;
219 prng.random.bytes(key[0..]);220 random.bytes(key[0..]);
220221
221 var nonce: [Aead.nonce_length]u8 = undefined;222 var nonce: [Aead.nonce_length]u8 = undefined;
222 prng.random.bytes(nonce[0..]);223 random.bytes(nonce[0..]);
223224
224 var offset: usize = 0;225 var offset: usize = 0;
225 var timer = try Timer.start();226 var timer = try Timer.start();
...@@ -244,7 +245,7 @@ const aes = [_]Crypto{...@@ -244,7 +245,7 @@ const aes = [_]Crypto{
244245
245pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {246pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {
246 var key: [Aes.key_bits / 8]u8 = undefined;247 var key: [Aes.key_bits / 8]u8 = undefined;
247 prng.random.bytes(key[0..]);248 random.bytes(key[0..]);
248 const ctx = Aes.initEnc(key);249 const ctx = Aes.initEnc(key);
249250
250 var in = [_]u8{0} ** 16;251 var in = [_]u8{0} ** 16;
...@@ -273,7 +274,7 @@ const aes8 = [_]Crypto{...@@ -273,7 +274,7 @@ const aes8 = [_]Crypto{
273274
274pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {275pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
275 var key: [Aes.key_bits / 8]u8 = undefined;276 var key: [Aes.key_bits / 8]u8 = undefined;
276 prng.random.bytes(key[0..]);277 random.bytes(key[0..]);
277 const ctx = Aes.initEnc(key);278 const ctx = Aes.initEnc(key);
278279
279 var in = [_]u8{0} ** (8 * 16);280 var in = [_]u8{0} ** (8 * 16);
lib/std/crypto/tlcsprng.zig+5-2
...@@ -11,7 +11,10 @@ const os = std.os;...@@ -11,7 +11,10 @@ const os = std.os;
1111
12/// We use this as a layer of indirection because global const pointers cannot12/// We use this as a layer of indirection because global const pointers cannot
13/// point to thread-local variables.13/// point to thread-local variables.
14pub var interface = std.rand.Random{ .fillFn = tlsCsprngFill };14pub const interface = std.rand.Random{
15 .ptr = undefined,
16 .fillFn = tlsCsprngFill,
17};
1518
16const os_has_fork = switch (builtin.os.tag) {19const os_has_fork = switch (builtin.os.tag) {
17 .dragonfly,20 .dragonfly,
...@@ -55,7 +58,7 @@ var install_atfork_handler = std.once(struct {...@@ -55,7 +58,7 @@ var install_atfork_handler = std.once(struct {
5558
56threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};59threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};
5760
58fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {61fn tlsCsprngFill(_: *c_void, buffer: []u8) void {
59 if (builtin.link_libc and @hasDecl(std.c, "arc4random_buf")) {62 if (builtin.link_libc and @hasDecl(std.c, "arc4random_buf")) {
60 // arc4random is already a thread-local CSPRNG.63 // arc4random is already a thread-local CSPRNG.
61 return std.c.arc4random_buf(buffer.ptr, buffer.len);64 return std.c.arc4random_buf(buffer.ptr, buffer.len);
lib/std/hash/benchmark.zig+3-2
...@@ -11,6 +11,7 @@ const MiB = 1024 * KiB;...@@ -11,6 +11,7 @@ const MiB = 1024 * KiB;
11const GiB = 1024 * MiB;11const GiB = 1024 * MiB;
1212
13var prng = std.rand.DefaultPrng.init(0);13var prng = std.rand.DefaultPrng.init(0);
14const random = prng.random();
1415
15const Hash = struct {16const Hash = struct {
16 ty: type,17 ty: type,
...@@ -88,7 +89,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize) !Result {...@@ -88,7 +89,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize) !Result {
88 };89 };
8990
90 var block: [block_size]u8 = undefined;91 var block: [block_size]u8 = undefined;
91 prng.random.bytes(block[0..]);92 random.bytes(block[0..]);
9293
93 var offset: usize = 0;94 var offset: usize = 0;
94 var timer = try Timer.start();95 var timer = try Timer.start();
...@@ -110,7 +111,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize) !Result {...@@ -110,7 +111,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize) !Result {
110pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize) !Result {111pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize) !Result {
111 const key_count = bytes / key_size;112 const key_count = bytes / key_size;
112 var block: [block_size]u8 = undefined;113 var block: [block_size]u8 = undefined;
113 prng.random.bytes(block[0..]);114 random.bytes(block[0..]);
114115
115 var i: usize = 0;116 var i: usize = 0;
116 var timer = try Timer.start();117 var timer = try Timer.start();
lib/std/hash_map.zig+7-5
...@@ -1795,10 +1795,11 @@ test "std.hash_map put and remove loop in random order" {...@@ -1795,10 +1795,11 @@ test "std.hash_map put and remove loop in random order" {
1795 while (i < size) : (i += 1) {1795 while (i < size) : (i += 1) {
1796 try keys.append(i);1796 try keys.append(i);
1797 }1797 }
1798 var rng = std.rand.DefaultPrng.init(0);1798 var prng = std.rand.DefaultPrng.init(0);
1799 const random = prng.random();
17991800
1800 while (i < iterations) : (i += 1) {1801 while (i < iterations) : (i += 1) {
1801 std.rand.Random.shuffle(&rng.random, u32, keys.items);1802 random.shuffle(u32, keys.items);
18021803
1803 for (keys.items) |key| {1804 for (keys.items) |key| {
1804 try map.put(key, key);1805 try map.put(key, key);
...@@ -1826,14 +1827,15 @@ test "std.hash_map remove one million elements in random order" {...@@ -1826,14 +1827,15 @@ test "std.hash_map remove one million elements in random order" {
1826 keys.append(i) catch unreachable;1827 keys.append(i) catch unreachable;
1827 }1828 }
18281829
1829 var rng = std.rand.DefaultPrng.init(0);1830 var prng = std.rand.DefaultPrng.init(0);
1830 std.rand.Random.shuffle(&rng.random, u32, keys.items);1831 const random = prng.random();
1832 random.shuffle(u32, keys.items);
18311833
1832 for (keys.items) |key| {1834 for (keys.items) |key| {
1833 map.put(key, key) catch unreachable;1835 map.put(key, key) catch unreachable;
1834 }1836 }
18351837
1836 std.rand.Random.shuffle(&rng.random, u32, keys.items);1838 random.shuffle(u32, keys.items);
1837 i = 0;1839 i = 0;
1838 while (i < n) : (i += 1) {1840 while (i < n) : (i += 1) {
1839 const key = keys.items[i];1841 const key = keys.items[i];
lib/std/io/test.zig+2-1
...@@ -20,7 +20,8 @@ test "write a file, read it, then delete it" {...@@ -20,7 +20,8 @@ test "write a file, read it, then delete it" {
2020
21 var data: [1024]u8 = undefined;21 var data: [1024]u8 = undefined;
22 var prng = DefaultPrng.init(1234);22 var prng = DefaultPrng.init(1234);
23 prng.random.bytes(data[0..]);23 const random = prng.random();
24 random.bytes(data[0..]);
24 const tmp_file_name = "temp_test_file.txt";25 const tmp_file_name = "temp_test_file.txt";
25 {26 {
26 var file = try tmp.dir.createFile(tmp_file_name, .{});27 var file = try tmp.dir.createFile(tmp_file_name, .{});
lib/std/math/big/rational.zig+2-1
...@@ -589,9 +589,10 @@ test "big.rational set/to Float round-trip" {...@@ -589,9 +589,10 @@ test "big.rational set/to Float round-trip" {
589 var a = try Rational.init(testing.allocator);589 var a = try Rational.init(testing.allocator);
590 defer a.deinit();590 defer a.deinit();
591 var prng = std.rand.DefaultPrng.init(0x5EED);591 var prng = std.rand.DefaultPrng.init(0x5EED);
592 const random = prng.random();
592 var i: usize = 0;593 var i: usize = 0;
593 while (i < 512) : (i += 1) {594 while (i < 512) : (i += 1) {
594 const r = prng.random.float(f64);595 const r = random.float(f64);
595 try a.setFloat(f64, r);596 try a.setFloat(f64, r);
596 try testing.expect((try a.toFloat(f64)) == r);597 try testing.expect((try a.toFloat(f64)) == r);
597 }598 }
lib/std/priority_dequeue.zig+10-7
...@@ -850,17 +850,18 @@ test "std.PriorityDequeue: shrinkAndFree" {...@@ -850,17 +850,18 @@ test "std.PriorityDequeue: shrinkAndFree" {
850850
851test "std.PriorityDequeue: fuzz testing min" {851test "std.PriorityDequeue: fuzz testing min" {
852 var prng = std.rand.DefaultPrng.init(0x12345678);852 var prng = std.rand.DefaultPrng.init(0x12345678);
853 const random = prng.random();
853854
854 const test_case_count = 100;855 const test_case_count = 100;
855 const queue_size = 1_000;856 const queue_size = 1_000;
856857
857 var i: usize = 0;858 var i: usize = 0;
858 while (i < test_case_count) : (i += 1) {859 while (i < test_case_count) : (i += 1) {
859 try fuzzTestMin(&prng.random, queue_size);860 try fuzzTestMin(random, queue_size);
860 }861 }
861}862}
862863
863fn fuzzTestMin(rng: *std.rand.Random, comptime queue_size: usize) !void {864fn fuzzTestMin(rng: std.rand.Random, comptime queue_size: usize) !void {
864 const allocator = testing.allocator;865 const allocator = testing.allocator;
865 const items = try generateRandomSlice(allocator, rng, queue_size);866 const items = try generateRandomSlice(allocator, rng, queue_size);
866867
...@@ -878,17 +879,18 @@ fn fuzzTestMin(rng: *std.rand.Random, comptime queue_size: usize) !void {...@@ -878,17 +879,18 @@ fn fuzzTestMin(rng: *std.rand.Random, comptime queue_size: usize) !void {
878879
879test "std.PriorityDequeue: fuzz testing max" {880test "std.PriorityDequeue: fuzz testing max" {
880 var prng = std.rand.DefaultPrng.init(0x87654321);881 var prng = std.rand.DefaultPrng.init(0x87654321);
882 const random = prng.random();
881883
882 const test_case_count = 100;884 const test_case_count = 100;
883 const queue_size = 1_000;885 const queue_size = 1_000;
884886
885 var i: usize = 0;887 var i: usize = 0;
886 while (i < test_case_count) : (i += 1) {888 while (i < test_case_count) : (i += 1) {
887 try fuzzTestMax(&prng.random, queue_size);889 try fuzzTestMax(random, queue_size);
888 }890 }
889}891}
890892
891fn fuzzTestMax(rng: *std.rand.Random, queue_size: usize) !void {893fn fuzzTestMax(rng: std.rand.Random, queue_size: usize) !void {
892 const allocator = testing.allocator;894 const allocator = testing.allocator;
893 const items = try generateRandomSlice(allocator, rng, queue_size);895 const items = try generateRandomSlice(allocator, rng, queue_size);
894896
...@@ -906,17 +908,18 @@ fn fuzzTestMax(rng: *std.rand.Random, queue_size: usize) !void {...@@ -906,17 +908,18 @@ fn fuzzTestMax(rng: *std.rand.Random, queue_size: usize) !void {
906908
907test "std.PriorityDequeue: fuzz testing min and max" {909test "std.PriorityDequeue: fuzz testing min and max" {
908 var prng = std.rand.DefaultPrng.init(0x87654321);910 var prng = std.rand.DefaultPrng.init(0x87654321);
911 const random = prng.random();
909912
910 const test_case_count = 100;913 const test_case_count = 100;
911 const queue_size = 1_000;914 const queue_size = 1_000;
912915
913 var i: usize = 0;916 var i: usize = 0;
914 while (i < test_case_count) : (i += 1) {917 while (i < test_case_count) : (i += 1) {
915 try fuzzTestMinMax(&prng.random, queue_size);918 try fuzzTestMinMax(random, queue_size);
916 }919 }
917}920}
918921
919fn fuzzTestMinMax(rng: *std.rand.Random, queue_size: usize) !void {922fn fuzzTestMinMax(rng: std.rand.Random, queue_size: usize) !void {
920 const allocator = testing.allocator;923 const allocator = testing.allocator;
921 const items = try generateRandomSlice(allocator, rng, queue_size);924 const items = try generateRandomSlice(allocator, rng, queue_size);
922925
...@@ -943,7 +946,7 @@ fn fuzzTestMinMax(rng: *std.rand.Random, queue_size: usize) !void {...@@ -943,7 +946,7 @@ fn fuzzTestMinMax(rng: *std.rand.Random, queue_size: usize) !void {
943 }946 }
944}947}
945948
946fn generateRandomSlice(allocator: *std.mem.Allocator, rng: *std.rand.Random, size: usize) ![]u32 {949fn generateRandomSlice(allocator: *std.mem.Allocator, rng: std.rand.Random, size: usize) ![]u32 {
947 var array = std.ArrayList(u32).init(allocator);950 var array = std.ArrayList(u32).init(allocator);
948 try array.ensureTotalCapacity(size);951 try array.ensureTotalCapacity(size);
949952
lib/std/rand.zig+195-159
...@@ -29,19 +29,40 @@ pub const Xoshiro256 = @import("rand/Xoshiro256.zig");...@@ -29,19 +29,40 @@ pub const Xoshiro256 = @import("rand/Xoshiro256.zig");
29pub const Sfc64 = @import("rand/Sfc64.zig");29pub const Sfc64 = @import("rand/Sfc64.zig");
3030
31pub const Random = struct {31pub const Random = struct {
32 fillFn: fn (r: *Random, buf: []u8) void,32 ptr: *c_void,
33 fillFn: fn (ptr: *c_void, buf: []u8) void,
34
35 pub fn init(pointer: anytype) Random {
36 const Ptr = @TypeOf(pointer);
37 assert(@typeInfo(Ptr) == .Pointer); // Must be a pointer
38 assert(@typeInfo(Ptr).Pointer.size == .One); // Must be a single-item pointer
39 assert(@typeInfo(@typeInfo(Ptr).Pointer.child) == .Struct); // Must point to a struct
40 assert(std.meta.trait.hasFn("fill")(@typeInfo(Ptr).Pointer.child)); // Struct must provide the `fill` function
41 const gen = struct {
42 fn fill(ptr: *c_void, buf: []u8) void {
43 const alignment = @typeInfo(Ptr).Pointer.alignment;
44 const self = @ptrCast(Ptr, @alignCast(alignment, ptr));
45 self.fill(buf);
46 }
47 };
48
49 return .{
50 .ptr = pointer,
51 .fillFn = gen.fill,
52 };
53 }
3354
34 /// Read random bytes into the specified buffer until full.55 /// Read random bytes into the specified buffer until full.
35 pub fn bytes(r: *Random, buf: []u8) void {56 pub fn bytes(r: Random, buf: []u8) void {
36 r.fillFn(r, buf);57 r.fillFn(r.ptr, buf);
37 }58 }
3859
39 pub fn boolean(r: *Random) bool {60 pub fn boolean(r: Random) bool {
40 return r.int(u1) != 0;61 return r.int(u1) != 0;
41 }62 }
4263
43 /// Returns a random value from an enum, evenly distributed.64 /// Returns a random value from an enum, evenly distributed.
44 pub fn enumValue(r: *Random, comptime EnumType: type) EnumType {65 pub fn enumValue(r: Random, comptime EnumType: type) EnumType {
45 if (comptime !std.meta.trait.is(.Enum)(EnumType)) {66 if (comptime !std.meta.trait.is(.Enum)(EnumType)) {
46 @compileError("Random.enumValue requires an enum type, not a " ++ @typeName(EnumType));67 @compileError("Random.enumValue requires an enum type, not a " ++ @typeName(EnumType));
47 }68 }
...@@ -55,7 +76,7 @@ pub const Random = struct {...@@ -55,7 +76,7 @@ pub const Random = struct {
5576
56 /// Returns a random int `i` such that `minInt(T) <= i <= maxInt(T)`.77 /// Returns a random int `i` such that `minInt(T) <= i <= maxInt(T)`.
57 /// `i` is evenly distributed.78 /// `i` is evenly distributed.
58 pub fn int(r: *Random, comptime T: type) T {79 pub fn int(r: Random, comptime T: type) T {
59 const bits = @typeInfo(T).Int.bits;80 const bits = @typeInfo(T).Int.bits;
60 const UnsignedT = std.meta.Int(.unsigned, bits);81 const UnsignedT = std.meta.Int(.unsigned, bits);
61 const ByteAlignedT = std.meta.Int(.unsigned, @divTrunc(bits + 7, 8) * 8);82 const ByteAlignedT = std.meta.Int(.unsigned, @divTrunc(bits + 7, 8) * 8);
...@@ -73,7 +94,7 @@ pub const Random = struct {...@@ -73,7 +94,7 @@ pub const Random = struct {
7394
74 /// Constant-time implementation off `uintLessThan`.95 /// Constant-time implementation off `uintLessThan`.
75 /// The results of this function may be biased.96 /// The results of this function may be biased.
76 pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {97 pub fn uintLessThanBiased(r: Random, comptime T: type, less_than: T) T {
77 comptime assert(@typeInfo(T).Int.signedness == .unsigned);98 comptime assert(@typeInfo(T).Int.signedness == .unsigned);
78 const bits = @typeInfo(T).Int.bits;99 const bits = @typeInfo(T).Int.bits;
79 comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!100 comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
...@@ -93,7 +114,7 @@ pub const Random = struct {...@@ -93,7 +114,7 @@ pub const Random = struct {
93 /// However, if `fillFn` is backed by any evenly distributed pseudo random number generator,114 /// However, if `fillFn` is backed by any evenly distributed pseudo random number generator,
94 /// this function is guaranteed to return.115 /// this function is guaranteed to return.
95 /// If you need deterministic runtime bounds, use `uintLessThanBiased`.116 /// If you need deterministic runtime bounds, use `uintLessThanBiased`.
96 pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {117 pub fn uintLessThan(r: Random, comptime T: type, less_than: T) T {
97 comptime assert(@typeInfo(T).Int.signedness == .unsigned);118 comptime assert(@typeInfo(T).Int.signedness == .unsigned);
98 const bits = @typeInfo(T).Int.bits;119 const bits = @typeInfo(T).Int.bits;
99 comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!120 comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
...@@ -130,7 +151,7 @@ pub const Random = struct {...@@ -130,7 +151,7 @@ pub const Random = struct {
130151
131 /// Constant-time implementation off `uintAtMost`.152 /// Constant-time implementation off `uintAtMost`.
132 /// The results of this function may be biased.153 /// The results of this function may be biased.
133 pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {154 pub fn uintAtMostBiased(r: Random, comptime T: type, at_most: T) T {
134 assert(@typeInfo(T).Int.signedness == .unsigned);155 assert(@typeInfo(T).Int.signedness == .unsigned);
135 if (at_most == maxInt(T)) {156 if (at_most == maxInt(T)) {
136 // have the full range157 // have the full range
...@@ -142,7 +163,7 @@ pub const Random = struct {...@@ -142,7 +163,7 @@ pub const Random = struct {
142 /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.163 /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
143 /// See `uintLessThan`, which this function uses in most cases,164 /// See `uintLessThan`, which this function uses in most cases,
144 /// for commentary on the runtime of this function.165 /// for commentary on the runtime of this function.
145 pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T {166 pub fn uintAtMost(r: Random, comptime T: type, at_most: T) T {
146 assert(@typeInfo(T).Int.signedness == .unsigned);167 assert(@typeInfo(T).Int.signedness == .unsigned);
147 if (at_most == maxInt(T)) {168 if (at_most == maxInt(T)) {
148 // have the full range169 // have the full range
...@@ -153,7 +174,7 @@ pub const Random = struct {...@@ -153,7 +174,7 @@ pub const Random = struct {
153174
154 /// Constant-time implementation off `intRangeLessThan`.175 /// Constant-time implementation off `intRangeLessThan`.
155 /// The results of this function may be biased.176 /// The results of this function may be biased.
156 pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {177 pub fn intRangeLessThanBiased(r: Random, comptime T: type, at_least: T, less_than: T) T {
157 assert(at_least < less_than);178 assert(at_least < less_than);
158 const info = @typeInfo(T).Int;179 const info = @typeInfo(T).Int;
159 if (info.signedness == .signed) {180 if (info.signedness == .signed) {
...@@ -172,7 +193,7 @@ pub const Random = struct {...@@ -172,7 +193,7 @@ pub const Random = struct {
172 /// Returns an evenly distributed random integer `at_least <= i < less_than`.193 /// Returns an evenly distributed random integer `at_least <= i < less_than`.
173 /// See `uintLessThan`, which this function uses in most cases,194 /// See `uintLessThan`, which this function uses in most cases,
174 /// for commentary on the runtime of this function.195 /// for commentary on the runtime of this function.
175 pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T {196 pub fn intRangeLessThan(r: Random, comptime T: type, at_least: T, less_than: T) T {
176 assert(at_least < less_than);197 assert(at_least < less_than);
177 const info = @typeInfo(T).Int;198 const info = @typeInfo(T).Int;
178 if (info.signedness == .signed) {199 if (info.signedness == .signed) {
...@@ -190,7 +211,7 @@ pub const Random = struct {...@@ -190,7 +211,7 @@ pub const Random = struct {
190211
191 /// Constant-time implementation off `intRangeAtMostBiased`.212 /// Constant-time implementation off `intRangeAtMostBiased`.
192 /// The results of this function may be biased.213 /// The results of this function may be biased.
193 pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {214 pub fn intRangeAtMostBiased(r: Random, comptime T: type, at_least: T, at_most: T) T {
194 assert(at_least <= at_most);215 assert(at_least <= at_most);
195 const info = @typeInfo(T).Int;216 const info = @typeInfo(T).Int;
196 if (info.signedness == .signed) {217 if (info.signedness == .signed) {
...@@ -209,7 +230,7 @@ pub const Random = struct {...@@ -209,7 +230,7 @@ pub const Random = struct {
209 /// Returns an evenly distributed random integer `at_least <= i <= at_most`.230 /// Returns an evenly distributed random integer `at_least <= i <= at_most`.
210 /// See `uintLessThan`, which this function uses in most cases,231 /// See `uintLessThan`, which this function uses in most cases,
211 /// for commentary on the runtime of this function.232 /// for commentary on the runtime of this function.
212 pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T {233 pub fn intRangeAtMost(r: Random, comptime T: type, at_least: T, at_most: T) T {
213 assert(at_least <= at_most);234 assert(at_least <= at_most);
214 const info = @typeInfo(T).Int;235 const info = @typeInfo(T).Int;
215 if (info.signedness == .signed) {236 if (info.signedness == .signed) {
...@@ -230,7 +251,7 @@ pub const Random = struct {...@@ -230,7 +251,7 @@ pub const Random = struct {
230 pub const range = @compileError("deprecated; use intRangeLessThan()");251 pub const range = @compileError("deprecated; use intRangeLessThan()");
231252
232 /// Return a floating point value evenly distributed in the range [0, 1).253 /// Return a floating point value evenly distributed in the range [0, 1).
233 pub fn float(r: *Random, comptime T: type) T {254 pub fn float(r: Random, comptime T: type) T {
234 // Generate a uniform value between [1, 2) and scale down to [0, 1).255 // Generate a uniform value between [1, 2) and scale down to [0, 1).
235 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.256 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
236 switch (T) {257 switch (T) {
...@@ -251,7 +272,7 @@ pub const Random = struct {...@@ -251,7 +272,7 @@ pub const Random = struct {
251 /// Return a floating point value normally distributed with mean = 0, stddev = 1.272 /// Return a floating point value normally distributed with mean = 0, stddev = 1.
252 ///273 ///
253 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.274 /// To use different parameters, use: floatNorm(...) * desiredStddev + desiredMean.
254 pub fn floatNorm(r: *Random, comptime T: type) T {275 pub fn floatNorm(r: Random, comptime T: type) T {
255 const value = ziggurat.next_f64(r, ziggurat.NormDist);276 const value = ziggurat.next_f64(r, ziggurat.NormDist);
256 switch (T) {277 switch (T) {
257 f32 => return @floatCast(f32, value),278 f32 => return @floatCast(f32, value),
...@@ -263,7 +284,7 @@ pub const Random = struct {...@@ -263,7 +284,7 @@ pub const Random = struct {
263 /// Return an exponentially distributed float with a rate parameter of 1.284 /// Return an exponentially distributed float with a rate parameter of 1.
264 ///285 ///
265 /// To use a different rate parameter, use: floatExp(...) / desiredRate.286 /// To use a different rate parameter, use: floatExp(...) / desiredRate.
266 pub fn floatExp(r: *Random, comptime T: type) T {287 pub fn floatExp(r: Random, comptime T: type) T {
267 const value = ziggurat.next_f64(r, ziggurat.ExpDist);288 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
268 switch (T) {289 switch (T) {
269 f32 => return @floatCast(f32, value),290 f32 => return @floatCast(f32, value),
...@@ -273,7 +294,7 @@ pub const Random = struct {...@@ -273,7 +294,7 @@ pub const Random = struct {
273 }294 }
274295
275 /// Shuffle a slice into a random order.296 /// Shuffle a slice into a random order.
276 pub fn shuffle(r: *Random, comptime T: type, buf: []T) void {297 pub fn shuffle(r: Random, comptime T: type, buf: []T) void {
277 if (buf.len < 2) {298 if (buf.len < 2) {
278 return;299 return;
279 }300 }
...@@ -303,18 +324,19 @@ pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {...@@ -303,18 +324,19 @@ pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
303324
304const SequentialPrng = struct {325const SequentialPrng = struct {
305 const Self = @This();326 const Self = @This();
306 random: Random,
307 next_value: u8,327 next_value: u8,
308328
309 pub fn init() Self {329 pub fn init() Self {
310 return Self{330 return Self{
311 .random = Random{ .fillFn = fill },
312 .next_value = 0,331 .next_value = 0,
313 };332 };
314 }333 }
315334
316 fn fill(r: *Random, buf: []u8) void {335 pub fn random(self: *Self) Random {
317 const self = @fieldParentPtr(Self, "random", r);336 return Random.init(self);
337 }
338
339 pub fn fill(self: *Self, buf: []u8) void {
318 for (buf) |*b| {340 for (buf) |*b| {
319 b.* = self.next_value;341 b.* = self.next_value;
320 }342 }
...@@ -327,45 +349,46 @@ test "Random int" {...@@ -327,45 +349,46 @@ test "Random int" {
327 comptime try testRandomInt();349 comptime try testRandomInt();
328}350}
329fn testRandomInt() !void {351fn testRandomInt() !void {
330 var r = SequentialPrng.init();352 var rng = SequentialPrng.init();
331353 const random = rng.random();
332 try expect(r.random.int(u0) == 0);354
333355 try expect(random.int(u0) == 0);
334 r.next_value = 0;356
335 try expect(r.random.int(u1) == 0);357 rng.next_value = 0;
336 try expect(r.random.int(u1) == 1);358 try expect(random.int(u1) == 0);
337 try expect(r.random.int(u2) == 2);359 try expect(random.int(u1) == 1);
338 try expect(r.random.int(u2) == 3);360 try expect(random.int(u2) == 2);
339 try expect(r.random.int(u2) == 0);361 try expect(random.int(u2) == 3);
340362 try expect(random.int(u2) == 0);
341 r.next_value = 0xff;363
342 try expect(r.random.int(u8) == 0xff);364 rng.next_value = 0xff;
343 r.next_value = 0x11;365 try expect(random.int(u8) == 0xff);
344 try expect(r.random.int(u8) == 0x11);366 rng.next_value = 0x11;
345367 try expect(random.int(u8) == 0x11);
346 r.next_value = 0xff;368
347 try expect(r.random.int(u32) == 0xffffffff);369 rng.next_value = 0xff;
348 r.next_value = 0x11;370 try expect(random.int(u32) == 0xffffffff);
349 try expect(r.random.int(u32) == 0x11111111);371 rng.next_value = 0x11;
350372 try expect(random.int(u32) == 0x11111111);
351 r.next_value = 0xff;373
352 try expect(r.random.int(i32) == -1);374 rng.next_value = 0xff;
353 r.next_value = 0x11;375 try expect(random.int(i32) == -1);
354 try expect(r.random.int(i32) == 0x11111111);376 rng.next_value = 0x11;
355377 try expect(random.int(i32) == 0x11111111);
356 r.next_value = 0xff;378
357 try expect(r.random.int(i8) == -1);379 rng.next_value = 0xff;
358 r.next_value = 0x11;380 try expect(random.int(i8) == -1);
359 try expect(r.random.int(i8) == 0x11);381 rng.next_value = 0x11;
360382 try expect(random.int(i8) == 0x11);
361 r.next_value = 0xff;383
362 try expect(r.random.int(u33) == 0x1ffffffff);384 rng.next_value = 0xff;
363 r.next_value = 0xff;385 try expect(random.int(u33) == 0x1ffffffff);
364 try expect(r.random.int(i1) == -1);386 rng.next_value = 0xff;
365 r.next_value = 0xff;387 try expect(random.int(i1) == -1);
366 try expect(r.random.int(i2) == -1);388 rng.next_value = 0xff;
367 r.next_value = 0xff;389 try expect(random.int(i2) == -1);
368 try expect(r.random.int(i33) == -1);390 rng.next_value = 0xff;
391 try expect(random.int(i33) == -1);
369}392}
370393
371test "Random boolean" {394test "Random boolean" {
...@@ -373,11 +396,13 @@ test "Random boolean" {...@@ -373,11 +396,13 @@ test "Random boolean" {
373 comptime try testRandomBoolean();396 comptime try testRandomBoolean();
374}397}
375fn testRandomBoolean() !void {398fn testRandomBoolean() !void {
376 var r = SequentialPrng.init();399 var rng = SequentialPrng.init();
377 try expect(r.random.boolean() == false);400 const random = rng.random();
378 try expect(r.random.boolean() == true);401
379 try expect(r.random.boolean() == false);402 try expect(random.boolean() == false);
380 try expect(r.random.boolean() == true);403 try expect(random.boolean() == true);
404 try expect(random.boolean() == false);
405 try expect(random.boolean() == true);
381}406}
382407
383test "Random enum" {408test "Random enum" {
...@@ -390,11 +415,12 @@ fn testRandomEnumValue() !void {...@@ -390,11 +415,12 @@ fn testRandomEnumValue() !void {
390 Second,415 Second,
391 Third,416 Third,
392 };417 };
393 var r = SequentialPrng.init();418 var rng = SequentialPrng.init();
394 r.next_value = 0;419 const random = rng.random();
395 try expect(r.random.enumValue(TestEnum) == TestEnum.First);420 rng.next_value = 0;
396 try expect(r.random.enumValue(TestEnum) == TestEnum.First);421 try expect(random.enumValue(TestEnum) == TestEnum.First);
397 try expect(r.random.enumValue(TestEnum) == TestEnum.First);422 try expect(random.enumValue(TestEnum) == TestEnum.First);
423 try expect(random.enumValue(TestEnum) == TestEnum.First);
398}424}
399425
400test "Random intLessThan" {426test "Random intLessThan" {
...@@ -403,38 +429,40 @@ test "Random intLessThan" {...@@ -403,38 +429,40 @@ test "Random intLessThan" {
403 comptime try testRandomIntLessThan();429 comptime try testRandomIntLessThan();
404}430}
405fn testRandomIntLessThan() !void {431fn testRandomIntLessThan() !void {
406 var r = SequentialPrng.init();432 var rng = SequentialPrng.init();
407 r.next_value = 0xff;433 const random = rng.random();
408 try expect(r.random.uintLessThan(u8, 4) == 3);434
409 try expect(r.next_value == 0);435 rng.next_value = 0xff;
410 try expect(r.random.uintLessThan(u8, 4) == 0);436 try expect(random.uintLessThan(u8, 4) == 3);
411 try expect(r.next_value == 1);437 try expect(rng.next_value == 0);
438 try expect(random.uintLessThan(u8, 4) == 0);
439 try expect(rng.next_value == 1);
412440
413 r.next_value = 0;441 rng.next_value = 0;
414 try expect(r.random.uintLessThan(u64, 32) == 0);442 try expect(random.uintLessThan(u64, 32) == 0);
415443
416 // trigger the bias rejection code path444 // trigger the bias rejection code path
417 r.next_value = 0;445 rng.next_value = 0;
418 try expect(r.random.uintLessThan(u8, 3) == 0);446 try expect(random.uintLessThan(u8, 3) == 0);
419 // verify we incremented twice447 // verify we incremented twice
420 try expect(r.next_value == 2);448 try expect(rng.next_value == 2);
421449
422 r.next_value = 0xff;450 rng.next_value = 0xff;
423 try expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);451 try expect(random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
424 r.next_value = 0xff;452 rng.next_value = 0xff;
425 try expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);453 try expect(random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe);
426454
427 r.next_value = 0xff;455 rng.next_value = 0xff;
428 try expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f);456 try expect(random.intRangeLessThan(i8, 0, 0x40) == 0x3f);
429 r.next_value = 0xff;457 rng.next_value = 0xff;
430 try expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);458 try expect(random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f);
431 r.next_value = 0xff;459 rng.next_value = 0xff;
432 try expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1);460 try expect(random.intRangeLessThan(i8, -0x80, 0) == -1);
433461
434 r.next_value = 0xff;462 rng.next_value = 0xff;
435 try expect(r.random.intRangeLessThan(i3, -4, 0) == -1);463 try expect(random.intRangeLessThan(i3, -4, 0) == -1);
436 r.next_value = 0xff;464 rng.next_value = 0xff;
437 try expect(r.random.intRangeLessThan(i3, -2, 2) == 1);465 try expect(random.intRangeLessThan(i3, -2, 2) == 1);
438}466}
439467
440test "Random intAtMost" {468test "Random intAtMost" {
...@@ -443,67 +471,70 @@ test "Random intAtMost" {...@@ -443,67 +471,70 @@ test "Random intAtMost" {
443 comptime try testRandomIntAtMost();471 comptime try testRandomIntAtMost();
444}472}
445fn testRandomIntAtMost() !void {473fn testRandomIntAtMost() !void {
446 var r = SequentialPrng.init();474 var rng = SequentialPrng.init();
447 r.next_value = 0xff;475 const random = rng.random();
448 try expect(r.random.uintAtMost(u8, 3) == 3);476
449 try expect(r.next_value == 0);477 rng.next_value = 0xff;
450 try expect(r.random.uintAtMost(u8, 3) == 0);478 try expect(random.uintAtMost(u8, 3) == 3);
479 try expect(rng.next_value == 0);
480 try expect(random.uintAtMost(u8, 3) == 0);
451481
452 // trigger the bias rejection code path482 // trigger the bias rejection code path
453 r.next_value = 0;483 rng.next_value = 0;
454 try expect(r.random.uintAtMost(u8, 2) == 0);484 try expect(random.uintAtMost(u8, 2) == 0);
455 // verify we incremented twice485 // verify we incremented twice
456 try expect(r.next_value == 2);486 try expect(rng.next_value == 2);
457487
458 r.next_value = 0xff;488 rng.next_value = 0xff;
459 try expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);489 try expect(random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
460 r.next_value = 0xff;490 rng.next_value = 0xff;
461 try expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);491 try expect(random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe);
462492
463 r.next_value = 0xff;493 rng.next_value = 0xff;
464 try expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);494 try expect(random.intRangeAtMost(i8, 0, 0x3f) == 0x3f);
465 r.next_value = 0xff;495 rng.next_value = 0xff;
466 try expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);496 try expect(random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f);
467 r.next_value = 0xff;497 rng.next_value = 0xff;
468 try expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1);498 try expect(random.intRangeAtMost(i8, -0x80, -1) == -1);
469499
470 r.next_value = 0xff;500 rng.next_value = 0xff;
471 try expect(r.random.intRangeAtMost(i3, -4, -1) == -1);501 try expect(random.intRangeAtMost(i3, -4, -1) == -1);
472 r.next_value = 0xff;502 rng.next_value = 0xff;
473 try expect(r.random.intRangeAtMost(i3, -2, 1) == 1);503 try expect(random.intRangeAtMost(i3, -2, 1) == 1);
474504
475 try expect(r.random.uintAtMost(u0, 0) == 0);505 try expect(random.uintAtMost(u0, 0) == 0);
476}506}
477507
478test "Random Biased" {508test "Random Biased" {
479 var r = DefaultPrng.init(0);509 var prng = DefaultPrng.init(0);
510 const random = prng.random();
480 // Not thoroughly checking the logic here.511 // Not thoroughly checking the logic here.
481 // Just want to execute all the paths with different types.512 // Just want to execute all the paths with different types.
482513
483 try expect(r.random.uintLessThanBiased(u1, 1) == 0);514 try expect(random.uintLessThanBiased(u1, 1) == 0);
484 try expect(r.random.uintLessThanBiased(u32, 10) < 10);515 try expect(random.uintLessThanBiased(u32, 10) < 10);
485 try expect(r.random.uintLessThanBiased(u64, 20) < 20);516 try expect(random.uintLessThanBiased(u64, 20) < 20);
486517
487 try expect(r.random.uintAtMostBiased(u0, 0) == 0);518 try expect(random.uintAtMostBiased(u0, 0) == 0);
488 try expect(r.random.uintAtMostBiased(u1, 0) <= 0);519 try expect(random.uintAtMostBiased(u1, 0) <= 0);
489 try expect(r.random.uintAtMostBiased(u32, 10) <= 10);520 try expect(random.uintAtMostBiased(u32, 10) <= 10);
490 try expect(r.random.uintAtMostBiased(u64, 20) <= 20);521 try expect(random.uintAtMostBiased(u64, 20) <= 20);
491522
492 try expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);523 try expect(random.intRangeLessThanBiased(u1, 0, 1) == 0);
493 try expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);524 try expect(random.intRangeLessThanBiased(i1, -1, 0) == -1);
494 try expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);525 try expect(random.intRangeLessThanBiased(u32, 10, 20) >= 10);
495 try expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);526 try expect(random.intRangeLessThanBiased(i32, 10, 20) >= 10);
496 try expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);527 try expect(random.intRangeLessThanBiased(u64, 20, 40) >= 20);
497 try expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);528 try expect(random.intRangeLessThanBiased(i64, 20, 40) >= 20);
498529
499 // uncomment for broken module error:530 // uncomment for broken module error:
500 //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);531 //expect(random.intRangeAtMostBiased(u0, 0, 0) == 0);
501 try expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);532 try expect(random.intRangeAtMostBiased(u1, 0, 1) >= 0);
502 try expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);533 try expect(random.intRangeAtMostBiased(i1, -1, 0) >= -1);
503 try expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);534 try expect(random.intRangeAtMostBiased(u32, 10, 20) >= 10);
504 try expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);535 try expect(random.intRangeAtMostBiased(i32, 10, 20) >= 10);
505 try expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);536 try expect(random.intRangeAtMostBiased(u64, 20, 40) >= 20);
506 try expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);537 try expect(random.intRangeAtMostBiased(i64, 20, 40) >= 20);
507}538}
508539
509// Generator to extend 64-bit seed values into longer sequences.540// Generator to extend 64-bit seed values into longer sequences.
...@@ -547,14 +578,15 @@ test "splitmix64 sequence" {...@@ -547,14 +578,15 @@ test "splitmix64 sequence" {
547// Actual Random helper function tests, pcg engine is assumed correct.578// Actual Random helper function tests, pcg engine is assumed correct.
548test "Random float" {579test "Random float" {
549 var prng = DefaultPrng.init(0);580 var prng = DefaultPrng.init(0);
581 const random = prng.random();
550582
551 var i: usize = 0;583 var i: usize = 0;
552 while (i < 1000) : (i += 1) {584 while (i < 1000) : (i += 1) {
553 const val1 = prng.random.float(f32);585 const val1 = random.float(f32);
554 try expect(val1 >= 0.0);586 try expect(val1 >= 0.0);
555 try expect(val1 < 1.0);587 try expect(val1 < 1.0);
556588
557 const val2 = prng.random.float(f64);589 const val2 = random.float(f64);
558 try expect(val2 >= 0.0);590 try expect(val2 >= 0.0);
559 try expect(val2 < 1.0);591 try expect(val2 < 1.0);
560 }592 }
...@@ -562,13 +594,14 @@ test "Random float" {...@@ -562,13 +594,14 @@ test "Random float" {
562594
563test "Random shuffle" {595test "Random shuffle" {
564 var prng = DefaultPrng.init(0);596 var prng = DefaultPrng.init(0);
597 const random = prng.random();
565598
566 var seq = [_]u8{ 0, 1, 2, 3, 4 };599 var seq = [_]u8{ 0, 1, 2, 3, 4 };
567 var seen = [_]bool{false} ** 5;600 var seen = [_]bool{false} ** 5;
568601
569 var i: usize = 0;602 var i: usize = 0;
570 while (i < 1000) : (i += 1) {603 while (i < 1000) : (i += 1) {
571 prng.random.shuffle(u8, seq[0..]);604 random.shuffle(u8, seq[0..]);
572 seen[seq[0]] = true;605 seen[seq[0]] = true;
573 try expect(sumArray(seq[0..]) == 10);606 try expect(sumArray(seq[0..]) == 10);
574 }607 }
...@@ -588,17 +621,19 @@ fn sumArray(s: []const u8) u32 {...@@ -588,17 +621,19 @@ fn sumArray(s: []const u8) u32 {
588621
589test "Random range" {622test "Random range" {
590 var prng = DefaultPrng.init(0);623 var prng = DefaultPrng.init(0);
591 try testRange(&prng.random, -4, 3);624 const random = prng.random();
592 try testRange(&prng.random, -4, -1);625
593 try testRange(&prng.random, 10, 14);626 try testRange(random, -4, 3);
594 try testRange(&prng.random, -0x80, 0x7f);627 try testRange(random, -4, -1);
628 try testRange(random, 10, 14);
629 try testRange(random, -0x80, 0x7f);
595}630}
596631
597fn testRange(r: *Random, start: i8, end: i8) !void {632fn testRange(r: Random, start: i8, end: i8) !void {
598 try testRangeBias(r, start, end, true);633 try testRangeBias(r, start, end, true);
599 try testRangeBias(r, start, end, false);634 try testRangeBias(r, start, end, false);
600}635}
601fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) !void {636fn testRangeBias(r: Random, start: i8, end: i8, biased: bool) !void {
602 const count = @intCast(usize, @as(i32, end) - @as(i32, start));637 const count = @intCast(usize, @as(i32, end) - @as(i32, start));
603 var values_buffer = [_]bool{false} ** 0x100;638 var values_buffer = [_]bool{false} ** 0x100;
604 const values = values_buffer[0..count];639 const values = values_buffer[0..count];
...@@ -617,9 +652,10 @@ test "CSPRNG" {...@@ -617,9 +652,10 @@ test "CSPRNG" {
617 var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;652 var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;
618 std.crypto.random.bytes(&secret_seed);653 std.crypto.random.bytes(&secret_seed);
619 var csprng = DefaultCsprng.init(secret_seed);654 var csprng = DefaultCsprng.init(secret_seed);
620 const a = csprng.random.int(u64);655 const random = csprng.random();
621 const b = csprng.random.int(u64);656 const a = random.int(u64);
622 const c = csprng.random.int(u64);657 const b = random.int(u64);
658 const c = random.int(u64);
623 try expect(a ^ b ^ c != 0);659 try expect(a ^ b ^ c != 0);
624}660}
625661
lib/std/rand/Gimli.zig+4-4
...@@ -5,7 +5,6 @@ const Random = std.rand.Random;...@@ -5,7 +5,6 @@ const Random = std.rand.Random;
5const mem = std.mem;5const mem = std.mem;
6const Gimli = @This();6const Gimli = @This();
77
8random: Random,
9state: std.crypto.core.Gimli,8state: std.crypto.core.Gimli,
109
11pub const secret_seed_length = 32;10pub const secret_seed_length = 32;
...@@ -16,15 +15,16 @@ pub fn init(secret_seed: [secret_seed_length]u8) Gimli {...@@ -16,15 +15,16 @@ pub fn init(secret_seed: [secret_seed_length]u8) Gimli {
16 mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);15 mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
17 mem.set(u8, initial_state[secret_seed_length..], 0);16 mem.set(u8, initial_state[secret_seed_length..], 0);
18 var self = Gimli{17 var self = Gimli{
19 .random = Random{ .fillFn = fill },
20 .state = std.crypto.core.Gimli.init(initial_state),18 .state = std.crypto.core.Gimli.init(initial_state),
21 };19 };
22 return self;20 return self;
23}21}
2422
25fn fill(r: *Random, buf: []u8) void {23pub fn random(self: *Gimli) Random {
26 const self = @fieldParentPtr(Gimli, "random", r);24 return Random.init(self);
25}
2726
27pub fn fill(self: *Gimli, buf: []u8) void {
28 if (buf.len != 0) {28 if (buf.len != 0) {
29 self.state.squeeze(buf);29 self.state.squeeze(buf);
30 } else {30 } else {
lib/std/rand/Isaac64.zig+6-7
...@@ -8,8 +8,6 @@ const Random = std.rand.Random;...@@ -8,8 +8,6 @@ const Random = std.rand.Random;
8const mem = std.mem;8const mem = std.mem;
9const Isaac64 = @This();9const Isaac64 = @This();
1010
11random: Random,
12
13r: [256]u64,11r: [256]u64,
14m: [256]u64,12m: [256]u64,
15a: u64,13a: u64,
...@@ -19,7 +17,6 @@ i: usize,...@@ -19,7 +17,6 @@ i: usize,
1917
20pub fn init(init_s: u64) Isaac64 {18pub fn init(init_s: u64) Isaac64 {
21 var isaac = Isaac64{19 var isaac = Isaac64{
22 .random = Random{ .fillFn = fill },
23 .r = undefined,20 .r = undefined,
24 .m = undefined,21 .m = undefined,
25 .a = undefined,22 .a = undefined,
...@@ -33,6 +30,10 @@ pub fn init(init_s: u64) Isaac64 {...@@ -33,6 +30,10 @@ pub fn init(init_s: u64) Isaac64 {
33 return isaac;30 return isaac;
34}31}
3532
33pub fn random(self: *Isaac64) Random {
34 return Random.init(self);
35}
36
36fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {37fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
37 const x = self.m[base + m1];38 const x = self.m[base + m1];
38 self.a = mix +% self.m[base + m2];39 self.a = mix +% self.m[base + m2];
...@@ -149,9 +150,7 @@ fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {...@@ -149,9 +150,7 @@ fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
149 self.i = self.r.len; // trigger refill on first value150 self.i = self.r.len; // trigger refill on first value
150}151}
151152
152fn fill(r: *Random, buf: []u8) void {153pub fn fill(self: *Isaac64, buf: []u8) void {
153 const self = @fieldParentPtr(Isaac64, "random", r);
154
155 var i: usize = 0;154 var i: usize = 0;
156 const aligned_len = buf.len - (buf.len & 7);155 const aligned_len = buf.len - (buf.len & 7);
157156
...@@ -230,7 +229,7 @@ test "isaac64 fill" {...@@ -230,7 +229,7 @@ test "isaac64 fill" {
230 var buf0: [8]u8 = undefined;229 var buf0: [8]u8 = undefined;
231 var buf1: [7]u8 = undefined;230 var buf1: [7]u8 = undefined;
232 std.mem.writeIntLittle(u64, &buf0, s);231 std.mem.writeIntLittle(u64, &buf0, s);
233 Isaac64.fill(&r.random, &buf1);232 r.fill(&buf1);
234 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));233 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
235 }234 }
236}235}
lib/std/rand/Pcg.zig+6-7
...@@ -8,14 +8,11 @@ const Pcg = @This();...@@ -8,14 +8,11 @@ const Pcg = @This();
88
9const default_multiplier = 6364136223846793005;9const default_multiplier = 6364136223846793005;
1010
11random: Random,
12
13s: u64,11s: u64,
14i: u64,12i: u64,
1513
16pub fn init(init_s: u64) Pcg {14pub fn init(init_s: u64) Pcg {
17 var pcg = Pcg{15 var pcg = Pcg{
18 .random = Random{ .fillFn = fill },
19 .s = undefined,16 .s = undefined,
20 .i = undefined,17 .i = undefined,
21 };18 };
...@@ -24,6 +21,10 @@ pub fn init(init_s: u64) Pcg {...@@ -24,6 +21,10 @@ pub fn init(init_s: u64) Pcg {
24 return pcg;21 return pcg;
25}22}
2623
24pub fn random(self: *Pcg) Random {
25 return Random.init(self);
26}
27
27fn next(self: *Pcg) u32 {28fn next(self: *Pcg) u32 {
28 const l = self.s;29 const l = self.s;
29 self.s = l *% default_multiplier +% (self.i | 1);30 self.s = l *% default_multiplier +% (self.i | 1);
...@@ -48,9 +49,7 @@ fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {...@@ -48,9 +49,7 @@ fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
48 self.s = self.s *% default_multiplier +% self.i;49 self.s = self.s *% default_multiplier +% self.i;
49}50}
5051
51fn fill(r: *Random, buf: []u8) void {52pub fn fill(self: *Pcg, buf: []u8) void {
52 const self = @fieldParentPtr(Pcg, "random", r);
53
54 var i: usize = 0;53 var i: usize = 0;
55 const aligned_len = buf.len - (buf.len & 7);54 const aligned_len = buf.len - (buf.len & 7);
5655
...@@ -113,7 +112,7 @@ test "pcg fill" {...@@ -113,7 +112,7 @@ test "pcg fill" {
113 var buf0: [4]u8 = undefined;112 var buf0: [4]u8 = undefined;
114 var buf1: [3]u8 = undefined;113 var buf1: [3]u8 = undefined;
115 std.mem.writeIntLittle(u32, &buf0, s);114 std.mem.writeIntLittle(u32, &buf0, s);
116 Pcg.fill(&r.random, &buf1);115 r.fill(&buf1);
117 try std.testing.expect(std.mem.eql(u8, buf0[0..3], buf1[0..]));116 try std.testing.expect(std.mem.eql(u8, buf0[0..3], buf1[0..]));
118 }117 }
119}118}
lib/std/rand/Sfc64.zig+7-9
...@@ -7,8 +7,6 @@ const Random = std.rand.Random;...@@ -7,8 +7,6 @@ const Random = std.rand.Random;
7const math = std.math;7const math = std.math;
8const Sfc64 = @This();8const Sfc64 = @This();
99
10random: Random,
11
12a: u64 = undefined,10a: u64 = undefined,
13b: u64 = undefined,11b: u64 = undefined,
14c: u64 = undefined,12c: u64 = undefined,
...@@ -19,14 +17,16 @@ const RightShift = 11;...@@ -19,14 +17,16 @@ const RightShift = 11;
19const LeftShift = 3;17const LeftShift = 3;
2018
21pub fn init(init_s: u64) Sfc64 {19pub fn init(init_s: u64) Sfc64 {
22 var x = Sfc64{20 var x = Sfc64{};
23 .random = Random{ .fillFn = fill },
24 };
2521
26 x.seed(init_s);22 x.seed(init_s);
27 return x;23 return x;
28}24}
2925
26pub fn random(self: *Sfc64) Random {
27 return Random.init(self);
28}
29
30fn next(self: *Sfc64) u64 {30fn next(self: *Sfc64) u64 {
31 const tmp = self.a +% self.b +% self.counter;31 const tmp = self.a +% self.b +% self.counter;
32 self.counter += 1;32 self.counter += 1;
...@@ -47,9 +47,7 @@ fn seed(self: *Sfc64, init_s: u64) void {...@@ -47,9 +47,7 @@ fn seed(self: *Sfc64, init_s: u64) void {
47 }47 }
48}48}
4949
50fn fill(r: *Random, buf: []u8) void {50pub fn fill(self: *Sfc64, buf: []u8) void {
51 const self = @fieldParentPtr(Sfc64, "random", r);
52
53 var i: usize = 0;51 var i: usize = 0;
54 const aligned_len = buf.len - (buf.len & 7);52 const aligned_len = buf.len - (buf.len & 7);
5553
...@@ -128,7 +126,7 @@ test "Sfc64 fill" {...@@ -128,7 +126,7 @@ test "Sfc64 fill" {
128 var buf0: [8]u8 = undefined;126 var buf0: [8]u8 = undefined;
129 var buf1: [7]u8 = undefined;127 var buf1: [7]u8 = undefined;
130 std.mem.writeIntLittle(u64, &buf0, s);128 std.mem.writeIntLittle(u64, &buf0, s);
131 Sfc64.fill(&r.random, &buf1);129 r.fill(&buf1);
132 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));130 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
133 }131 }
134}132}
lib/std/rand/Xoroshiro128.zig+7-10
...@@ -7,20 +7,19 @@ const Random = std.rand.Random;...@@ -7,20 +7,19 @@ const Random = std.rand.Random;
7const math = std.math;7const math = std.math;
8const Xoroshiro128 = @This();8const Xoroshiro128 = @This();
99
10random: Random,
11
12s: [2]u64,10s: [2]u64,
1311
14pub fn init(init_s: u64) Xoroshiro128 {12pub fn init(init_s: u64) Xoroshiro128 {
15 var x = Xoroshiro128{13 var x = Xoroshiro128{ .s = undefined };
16 .random = Random{ .fillFn = fill },
17 .s = undefined,
18 };
1914
20 x.seed(init_s);15 x.seed(init_s);
21 return x;16 return x;
22}17}
2318
19pub fn random(self: *Xoroshiro128) Random {
20 return Random.init(self);
21}
22
24fn next(self: *Xoroshiro128) u64 {23fn next(self: *Xoroshiro128) u64 {
25 const s0 = self.s[0];24 const s0 = self.s[0];
26 var s1 = self.s[1];25 var s1 = self.s[1];
...@@ -66,9 +65,7 @@ pub fn seed(self: *Xoroshiro128, init_s: u64) void {...@@ -66,9 +65,7 @@ pub fn seed(self: *Xoroshiro128, init_s: u64) void {
66 self.s[1] = gen.next();65 self.s[1] = gen.next();
67}66}
6867
69fn fill(r: *Random, buf: []u8) void {68pub fn fill(self: *Xoroshiro128, buf: []u8) void {
70 const self = @fieldParentPtr(Xoroshiro128, "random", r);
71
72 var i: usize = 0;69 var i: usize = 0;
73 const aligned_len = buf.len - (buf.len & 7);70 const aligned_len = buf.len - (buf.len & 7);
7471
...@@ -144,7 +141,7 @@ test "xoroshiro fill" {...@@ -144,7 +141,7 @@ test "xoroshiro fill" {
144 var buf0: [8]u8 = undefined;141 var buf0: [8]u8 = undefined;
145 var buf1: [7]u8 = undefined;142 var buf1: [7]u8 = undefined;
146 std.mem.writeIntLittle(u64, &buf0, s);143 std.mem.writeIntLittle(u64, &buf0, s);
147 Xoroshiro128.fill(&r.random, &buf1);144 r.fill(&buf1);
148 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));145 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
149 }146 }
150}147}
lib/std/rand/Xoshiro256.zig+6-7
...@@ -7,13 +7,10 @@ const Random = std.rand.Random;...@@ -7,13 +7,10 @@ const Random = std.rand.Random;
7const math = std.math;7const math = std.math;
8const Xoshiro256 = @This();8const Xoshiro256 = @This();
99
10random: Random,
11
12s: [4]u64,10s: [4]u64,
1311
14pub fn init(init_s: u64) Xoshiro256 {12pub fn init(init_s: u64) Xoshiro256 {
15 var x = Xoshiro256{13 var x = Xoshiro256{
16 .random = Random{ .fillFn = fill },
17 .s = undefined,14 .s = undefined,
18 };15 };
1916
...@@ -21,6 +18,10 @@ pub fn init(init_s: u64) Xoshiro256 {...@@ -21,6 +18,10 @@ pub fn init(init_s: u64) Xoshiro256 {
21 return x;18 return x;
22}19}
2320
21pub fn random(self: *Xoshiro256) Random {
22 return Random.init(self);
23}
24
24fn next(self: *Xoshiro256) u64 {25fn next(self: *Xoshiro256) u64 {
25 const r = math.rotl(u64, self.s[0] +% self.s[3], 23) +% self.s[0];26 const r = math.rotl(u64, self.s[0] +% self.s[3], 23) +% self.s[0];
2627
...@@ -64,9 +65,7 @@ pub fn seed(self: *Xoshiro256, init_s: u64) void {...@@ -64,9 +65,7 @@ pub fn seed(self: *Xoshiro256, init_s: u64) void {
64 self.s[3] = gen.next();65 self.s[3] = gen.next();
65}66}
6667
67fn fill(r: *Random, buf: []u8) void {68pub fn fill(self: *Xoshiro256, buf: []u8) void {
68 const self = @fieldParentPtr(Xoshiro256, "random", r);
69
70 var i: usize = 0;69 var i: usize = 0;
71 const aligned_len = buf.len - (buf.len & 7);70 const aligned_len = buf.len - (buf.len & 7);
7271
...@@ -138,7 +137,7 @@ test "xoroshiro fill" {...@@ -138,7 +137,7 @@ test "xoroshiro fill" {
138 var buf0: [8]u8 = undefined;137 var buf0: [8]u8 = undefined;
139 var buf1: [7]u8 = undefined;138 var buf1: [7]u8 = undefined;
140 std.mem.writeIntLittle(u64, &buf0, s);139 std.mem.writeIntLittle(u64, &buf0, s);
141 Xoshiro256.fill(&r.random, &buf1);140 r.fill(&buf1);
142 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));141 try std.testing.expect(std.mem.eql(u8, buf0[0..7], buf1[0..]));
143 }142 }
144}143}
lib/std/rand/ziggurat.zig+11-7
...@@ -13,7 +13,7 @@ const builtin = @import("builtin");...@@ -13,7 +13,7 @@ const builtin = @import("builtin");
13const math = std.math;13const math = std.math;
14const Random = std.rand.Random;14const Random = std.rand.Random;
1515
16pub fn next_f64(random: *Random, comptime tables: ZigTable) f64 {16pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {
17 while (true) {17 while (true) {
18 // We manually construct a float from parts as we can avoid an extra random lookup here by18 // We manually construct a float from parts as we can avoid an extra random lookup here by
19 // using the unused exponent for the lookup table entry.19 // using the unused exponent for the lookup table entry.
...@@ -61,7 +61,7 @@ pub const ZigTable = struct {...@@ -61,7 +61,7 @@ pub const ZigTable = struct {
61 // whether the distribution is symmetric61 // whether the distribution is symmetric
62 is_symmetric: bool,62 is_symmetric: bool,
63 // fallback calculation in the case we are in the 0 block63 // fallback calculation in the case we are in the 0 block
64 zero_case: fn (*Random, f64) f64,64 zero_case: fn (Random, f64) f64,
65};65};
6666
67// zigNorInit67// zigNorInit
...@@ -71,7 +71,7 @@ fn ZigTableGen(...@@ -71,7 +71,7 @@ fn ZigTableGen(
71 comptime v: f64,71 comptime v: f64,
72 comptime f: fn (f64) f64,72 comptime f: fn (f64) f64,
73 comptime f_inv: fn (f64) f64,73 comptime f_inv: fn (f64) f64,
74 comptime zero_case: fn (*Random, f64) f64,74 comptime zero_case: fn (Random, f64) f64,
75) ZigTable {75) ZigTable {
76 var tables: ZigTable = undefined;76 var tables: ZigTable = undefined;
7777
...@@ -111,7 +111,7 @@ fn norm_f(x: f64) f64 {...@@ -111,7 +111,7 @@ fn norm_f(x: f64) f64 {
111fn norm_f_inv(y: f64) f64 {111fn norm_f_inv(y: f64) f64 {
112 return math.sqrt(-2.0 * math.ln(y));112 return math.sqrt(-2.0 * math.ln(y));
113}113}
114fn norm_zero_case(random: *Random, u: f64) f64 {114fn norm_zero_case(random: Random, u: f64) f64 {
115 var x: f64 = 1;115 var x: f64 = 1;
116 var y: f64 = 0;116 var y: f64 = 0;
117117
...@@ -133,9 +133,11 @@ test "normal dist sanity" {...@@ -133,9 +133,11 @@ test "normal dist sanity" {
133 if (please_windows_dont_oom) return error.SkipZigTest;133 if (please_windows_dont_oom) return error.SkipZigTest;
134134
135 var prng = std.rand.DefaultPrng.init(0);135 var prng = std.rand.DefaultPrng.init(0);
136 const random = prng.random();
137
136 var i: usize = 0;138 var i: usize = 0;
137 while (i < 1000) : (i += 1) {139 while (i < 1000) : (i += 1) {
138 _ = prng.random.floatNorm(f64);140 _ = random.floatNorm(f64);
139 }141 }
140}142}
141143
...@@ -154,7 +156,7 @@ fn exp_f(x: f64) f64 {...@@ -154,7 +156,7 @@ fn exp_f(x: f64) f64 {
154fn exp_f_inv(y: f64) f64 {156fn exp_f_inv(y: f64) f64 {
155 return -math.ln(y);157 return -math.ln(y);
156}158}
157fn exp_zero_case(random: *Random, _: f64) f64 {159fn exp_zero_case(random: Random, _: f64) f64 {
158 return exp_r - math.ln(random.float(f64));160 return exp_r - math.ln(random.float(f64));
159}161}
160162
...@@ -162,9 +164,11 @@ test "exp dist sanity" {...@@ -162,9 +164,11 @@ test "exp dist sanity" {
162 if (please_windows_dont_oom) return error.SkipZigTest;164 if (please_windows_dont_oom) return error.SkipZigTest;
163165
164 var prng = std.rand.DefaultPrng.init(0);166 var prng = std.rand.DefaultPrng.init(0);
167 const random = prng.random();
168
165 var i: usize = 0;169 var i: usize = 0;
166 while (i < 1000) : (i += 1) {170 while (i < 1000) : (i += 1) {
167 _ = prng.random.floatExp(f64);171 _ = random.floatExp(f64);
168 }172 }
169}173}
170174
lib/std/sort.zig+3-2
...@@ -1328,16 +1328,17 @@ test "another sort case" {...@@ -1328,16 +1328,17 @@ test "another sort case" {
13281328
1329test "sort fuzz testing" {1329test "sort fuzz testing" {
1330 var prng = std.rand.DefaultPrng.init(0x12345678);1330 var prng = std.rand.DefaultPrng.init(0x12345678);
1331 const random = prng.random();
1331 const test_case_count = 10;1332 const test_case_count = 10;
1332 var i: usize = 0;1333 var i: usize = 0;
1333 while (i < test_case_count) : (i += 1) {1334 while (i < test_case_count) : (i += 1) {
1334 try fuzzTest(&prng.random);1335 try fuzzTest(random);
1335 }1336 }
1336}1337}
13371338
1338var fixed_buffer_mem: [100 * 1024]u8 = undefined;1339var fixed_buffer_mem: [100 * 1024]u8 = undefined;
13391340
1340fn fuzzTest(rng: *std.rand.Random) !void {1341fn fuzzTest(rng: std.rand.Random) !void {
1341 const array_size = rng.intRangeLessThan(usize, 0, 1000);1342 const array_size = rng.intRangeLessThan(usize, 0, 1000);
1342 var array = try testing.allocator.alloc(IdAndValue, array_size);1343 var array = try testing.allocator.alloc(IdAndValue, array_size);
1343 defer testing.allocator.free(array);1344 defer testing.allocator.free(array);