| author | |
| committer | |
| log | c1a5ff34f3f68a2a0bc32828ab483328cd436fea |
| tree | bad85387a89da38890f72696ccfc0ae3c416ab0f |
| parent | 9024f27d8f5cb651e2260348ce0ee6fd67fc2c32 |
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" { |
| 242 | 242 | ||
| 243 | fn startPuts(ctx: *Context) u8 { | 243 | fn 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 fuzz | 248 | 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" { |
| 147 | 147 | ||
| 148 | fn startPuts(ctx: *Context) u8 { | 148 | fn 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 fuzz | 153 | 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; |
| 11 | const MiB = 1024 * KiB; | 11 | const MiB = 1024 * KiB; |
| 12 | 12 | ||
| 13 | var prng = std.rand.DefaultPrng.init(0); | 13 | var prng = std.rand.DefaultPrng.init(0); |
| 14 | const random = prng.random(); | ||
| 14 | 15 | ||
| 15 | const Crypto = struct { | 16 | const 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(.{}); |
| 35 | 36 | ||
| 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..]); |
| 38 | 39 | ||
| 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{ |
| 66 | 67 | ||
| 67 | pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { | 68 | pub 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..]); |
| 70 | 71 | ||
| 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..]); |
| 74 | 75 | ||
| 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); |
| 95 | 96 | ||
| 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..]); |
| 98 | 99 | ||
| 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..]); |
| 101 | 102 | ||
| 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{ |
| 211 | 212 | ||
| 212 | pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 { | 213 | pub 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..]); |
| 215 | 216 | ||
| 216 | var tag: [Aead.tag_length]u8 = undefined; | 217 | var tag: [Aead.tag_length]u8 = undefined; |
| 217 | 218 | ||
| 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..]); |
| 220 | 221 | ||
| 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..]); |
| 223 | 224 | ||
| 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{ |
| 244 | 245 | ||
| 245 | pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 { | 246 | pub 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); |
| 249 | 250 | ||
| 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{ |
| 273 | 274 | ||
| 274 | pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 { | 275 | pub 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); |
| 278 | 279 | ||
| 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; |
| 11 | 11 | ||
| 12 | /// We use this as a layer of indirection because global const pointers cannot | 12 | /// 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. |
| 14 | pub var interface = std.rand.Random{ .fillFn = tlsCsprngFill }; | 14 | pub const interface = std.rand.Random{ |
| 15 | .ptr = undefined, | ||
| 16 | .fillFn = tlsCsprngFill, | ||
| 17 | }; | ||
| 15 | 18 | ||
| 16 | const os_has_fork = switch (builtin.os.tag) { | 19 | const 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 { |
| 55 | 58 | ||
| 56 | threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{}; | 59 | threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{}; |
| 57 | 60 | ||
| 58 | fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void { | 61 | fn 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; |
| 11 | const GiB = 1024 * MiB; | 11 | const GiB = 1024 * MiB; |
| 12 | 12 | ||
| 13 | var prng = std.rand.DefaultPrng.init(0); | 13 | var prng = std.rand.DefaultPrng.init(0); |
| 14 | const random = prng.random(); | ||
| 14 | 15 | ||
| 15 | const Hash = struct { | 16 | const 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 | }; |
| 89 | 90 | ||
| 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..]); |
| 92 | 93 | ||
| 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 { |
| 110 | pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize) !Result { | 111 | pub 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..]); |
| 114 | 115 | ||
| 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(); | ||
| 1799 | 1800 | ||
| 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); |
| 1802 | 1803 | ||
| 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 | } |
| 1828 | 1829 | ||
| 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); | ||
| 1831 | 1833 | ||
| 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 | } |
| 1835 | 1837 | ||
| 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" { |
| 20 | 20 | ||
| 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" { |
| 850 | 850 | ||
| 851 | test "std.PriorityDequeue: fuzz testing min" { | 851 | test "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(); | ||
| 853 | 854 | ||
| 854 | const test_case_count = 100; | 855 | const test_case_count = 100; |
| 855 | const queue_size = 1_000; | 856 | const queue_size = 1_000; |
| 856 | 857 | ||
| 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 | } |
| 862 | 863 | ||
| 863 | fn fuzzTestMin(rng: *std.rand.Random, comptime queue_size: usize) !void { | 864 | fn 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); |
| 866 | 867 | ||
| ... | @@ -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 { |
| 878 | 879 | ||
| 879 | test "std.PriorityDequeue: fuzz testing max" { | 880 | test "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(); | ||
| 881 | 883 | ||
| 882 | const test_case_count = 100; | 884 | const test_case_count = 100; |
| 883 | const queue_size = 1_000; | 885 | const queue_size = 1_000; |
| 884 | 886 | ||
| 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 | } |
| 890 | 892 | ||
| 891 | fn fuzzTestMax(rng: *std.rand.Random, queue_size: usize) !void { | 893 | fn 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); |
| 894 | 896 | ||
| ... | @@ -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 { |
| 906 | 908 | ||
| 907 | test "std.PriorityDequeue: fuzz testing min and max" { | 909 | test "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(); | ||
| 909 | 912 | ||
| 910 | const test_case_count = 100; | 913 | const test_case_count = 100; |
| 911 | const queue_size = 1_000; | 914 | const queue_size = 1_000; |
| 912 | 915 | ||
| 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 | } |
| 918 | 921 | ||
| 919 | fn fuzzTestMinMax(rng: *std.rand.Random, queue_size: usize) !void { | 922 | fn 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); |
| 922 | 925 | ||
| ... | @@ -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 | } |
| 945 | 948 | ||
| 946 | fn generateRandomSlice(allocator: *std.mem.Allocator, rng: *std.rand.Random, size: usize) ![]u32 { | 949 | fn 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); |
| 949 | 952 |
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"); |
| 29 | pub const Sfc64 = @import("rand/Sfc64.zig"); | 29 | pub const Sfc64 = @import("rand/Sfc64.zig"); |
| 30 | 30 | ||
| 31 | pub const Random = struct { | 31 | pub 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 | } | ||
| 33 | 54 | ||
| 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 | } |
| 38 | 59 | ||
| 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 | } |
| 42 | 63 | ||
| 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 { |
| 55 | 76 | ||
| 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 { |
| 73 | 94 | ||
| 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 { |
| 130 | 151 | ||
| 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 range | 157 | // 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 range | 169 | // have the full range |
| ... | @@ -153,7 +174,7 @@ pub const Random = struct { | ... | @@ -153,7 +174,7 @@ pub const Random = struct { |
| 153 | 174 | ||
| 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 { |
| 190 | 211 | ||
| 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()"); |
| 231 | 252 | ||
| 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 | } |
| 274 | 295 | ||
| 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 { |
| 303 | 324 | ||
| 304 | const SequentialPrng = struct { | 325 | const SequentialPrng = struct { |
| 305 | const Self = @This(); | 326 | const Self = @This(); |
| 306 | random: Random, | ||
| 307 | next_value: u8, | 327 | next_value: u8, |
| 308 | 328 | ||
| 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 | } |
| 315 | 334 | ||
| 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 | } |
| 329 | fn testRandomInt() !void { | 351 | fn testRandomInt() !void { |
| 330 | var r = SequentialPrng.init(); | 352 | var rng = SequentialPrng.init(); |
| 331 | 353 | const random = rng.random(); | |
| 332 | try expect(r.random.int(u0) == 0); | 354 | |
| 333 | 355 | 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); |
| 340 | 362 | 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; |
| 345 | 367 | 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; |
| 350 | 372 | 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; |
| 355 | 377 | 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; |
| 360 | 382 | 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 | } |
| 370 | 393 | ||
| 371 | test "Random boolean" { | 394 | test "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 | } |
| 375 | fn testRandomBoolean() !void { | 398 | fn 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 | } |
| 382 | 407 | ||
| 383 | test "Random enum" { | 408 | test "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 | } |
| 399 | 425 | ||
| 400 | test "Random intLessThan" { | 426 | test "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 | } |
| 405 | fn testRandomIntLessThan() !void { | 431 | fn 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); | ||
| 412 | 440 | ||
| 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); |
| 415 | 443 | ||
| 416 | // trigger the bias rejection code path | 444 | // 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 twice | 447 | // verify we incremented twice |
| 420 | try expect(r.next_value == 2); | 448 | try expect(rng.next_value == 2); |
| 421 | 449 | ||
| 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); |
| 426 | 454 | ||
| 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); |
| 433 | 461 | ||
| 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 | } |
| 439 | 467 | ||
| 440 | test "Random intAtMost" { | 468 | test "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 | } |
| 445 | fn testRandomIntAtMost() !void { | 473 | fn 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); | ||
| 451 | 481 | ||
| 452 | // trigger the bias rejection code path | 482 | // 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 twice | 485 | // verify we incremented twice |
| 456 | try expect(r.next_value == 2); | 486 | try expect(rng.next_value == 2); |
| 457 | 487 | ||
| 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); |
| 462 | 492 | ||
| 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); |
| 469 | 499 | ||
| 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); |
| 474 | 504 | ||
| 475 | try expect(r.random.uintAtMost(u0, 0) == 0); | 505 | try expect(random.uintAtMost(u0, 0) == 0); |
| 476 | } | 506 | } |
| 477 | 507 | ||
| 478 | test "Random Biased" { | 508 | test "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. |
| 482 | 513 | ||
| 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); |
| 486 | 517 | ||
| 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); |
| 491 | 522 | ||
| 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); |
| 498 | 529 | ||
| 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 | } |
| 508 | 539 | ||
| 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. |
| 548 | test "Random float" { | 579 | test "Random float" { |
| 549 | var prng = DefaultPrng.init(0); | 580 | var prng = DefaultPrng.init(0); |
| 581 | const random = prng.random(); | ||
| 550 | 582 | ||
| 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); |
| 556 | 588 | ||
| 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" { |
| 562 | 594 | ||
| 563 | test "Random shuffle" { | 595 | test "Random shuffle" { |
| 564 | var prng = DefaultPrng.init(0); | 596 | var prng = DefaultPrng.init(0); |
| 597 | const random = prng.random(); | ||
| 565 | 598 | ||
| 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; |
| 568 | 601 | ||
| 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 { |
| 588 | 621 | ||
| 589 | test "Random range" { | 622 | test "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 | } |
| 596 | 631 | ||
| 597 | fn testRange(r: *Random, start: i8, end: i8) !void { | 632 | fn 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 | } |
| 601 | fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) !void { | 636 | fn 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 | } |
| 625 | 661 |
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; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const Gimli = @This(); | 6 | const Gimli = @This(); |
| 7 | 7 | ||
| 8 | random: Random, | ||
| 9 | state: std.crypto.core.Gimli, | 8 | state: std.crypto.core.Gimli, |
| 10 | 9 | ||
| 11 | pub const secret_seed_length = 32; | 10 | pub 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 | } |
| 24 | 22 | ||
| 25 | fn fill(r: *Random, buf: []u8) void { | 23 | pub fn random(self: *Gimli) Random { |
| 26 | const self = @fieldParentPtr(Gimli, "random", r); | 24 | return Random.init(self); |
| 25 | } | ||
| 27 | 26 | ||
| 27 | pub 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; |
| 8 | const mem = std.mem; | 8 | const mem = std.mem; |
| 9 | const Isaac64 = @This(); | 9 | const Isaac64 = @This(); |
| 10 | 10 | ||
| 11 | random: Random, | ||
| 12 | |||
| 13 | r: [256]u64, | 11 | r: [256]u64, |
| 14 | m: [256]u64, | 12 | m: [256]u64, |
| 15 | a: u64, | 13 | a: u64, |
| ... | @@ -19,7 +17,6 @@ i: usize, | ... | @@ -19,7 +17,6 @@ i: usize, |
| 19 | 17 | ||
| 20 | pub fn init(init_s: u64) Isaac64 { | 18 | pub 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 | } |
| 35 | 32 | ||
| 33 | pub fn random(self: *Isaac64) Random { | ||
| 34 | return Random.init(self); | ||
| 35 | } | ||
| 36 | |||
| 36 | fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void { | 37 | fn 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 value | 150 | self.i = self.r.len; // trigger refill on first value |
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | fn fill(r: *Random, buf: []u8) void { | 153 | pub 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); |
| 157 | 156 | ||
| ... | @@ -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(); |
| 8 | 8 | ||
| 9 | const default_multiplier = 6364136223846793005; | 9 | const default_multiplier = 6364136223846793005; |
| 10 | 10 | ||
| 11 | random: Random, | ||
| 12 | |||
| 13 | s: u64, | 11 | s: u64, |
| 14 | i: u64, | 12 | i: u64, |
| 15 | 13 | ||
| 16 | pub fn init(init_s: u64) Pcg { | 14 | pub 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 | } |
| 26 | 23 | ||
| 24 | pub fn random(self: *Pcg) Random { | ||
| 25 | return Random.init(self); | ||
| 26 | } | ||
| 27 | |||
| 27 | fn next(self: *Pcg) u32 { | 28 | fn 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 | } |
| 50 | 51 | ||
| 51 | fn fill(r: *Random, buf: []u8) void { | 52 | pub 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); |
| 56 | 55 | ||
| ... | @@ -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; |
| 7 | const math = std.math; | 7 | const math = std.math; |
| 8 | const Sfc64 = @This(); | 8 | const Sfc64 = @This(); |
| 9 | 9 | ||
| 10 | random: Random, | ||
| 11 | |||
| 12 | a: u64 = undefined, | 10 | a: u64 = undefined, |
| 13 | b: u64 = undefined, | 11 | b: u64 = undefined, |
| 14 | c: u64 = undefined, | 12 | c: u64 = undefined, |
| ... | @@ -19,14 +17,16 @@ const RightShift = 11; | ... | @@ -19,14 +17,16 @@ const RightShift = 11; |
| 19 | const LeftShift = 3; | 17 | const LeftShift = 3; |
| 20 | 18 | ||
| 21 | pub fn init(init_s: u64) Sfc64 { | 19 | pub fn init(init_s: u64) Sfc64 { |
| 22 | var x = Sfc64{ | 20 | var x = Sfc64{}; |
| 23 | .random = Random{ .fillFn = fill }, | ||
| 24 | }; | ||
| 25 | 21 | ||
| 26 | x.seed(init_s); | 22 | x.seed(init_s); |
| 27 | return x; | 23 | return x; |
| 28 | } | 24 | } |
| 29 | 25 | ||
| 26 | pub fn random(self: *Sfc64) Random { | ||
| 27 | return Random.init(self); | ||
| 28 | } | ||
| 29 | |||
| 30 | fn next(self: *Sfc64) u64 { | 30 | fn 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 | } |
| 49 | 49 | ||
| 50 | fn fill(r: *Random, buf: []u8) void { | 50 | pub 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); |
| 55 | 53 | ||
| ... | @@ -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; |
| 7 | const math = std.math; | 7 | const math = std.math; |
| 8 | const Xoroshiro128 = @This(); | 8 | const Xoroshiro128 = @This(); |
| 9 | 9 | ||
| 10 | random: Random, | ||
| 11 | |||
| 12 | s: [2]u64, | 10 | s: [2]u64, |
| 13 | 11 | ||
| 14 | pub fn init(init_s: u64) Xoroshiro128 { | 12 | pub 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 | }; | ||
| 19 | 14 | ||
| 20 | x.seed(init_s); | 15 | x.seed(init_s); |
| 21 | return x; | 16 | return x; |
| 22 | } | 17 | } |
| 23 | 18 | ||
| 19 | pub fn random(self: *Xoroshiro128) Random { | ||
| 20 | return Random.init(self); | ||
| 21 | } | ||
| 22 | |||
| 24 | fn next(self: *Xoroshiro128) u64 { | 23 | fn 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 | } |
| 68 | 67 | ||
| 69 | fn fill(r: *Random, buf: []u8) void { | 68 | pub 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); |
| 74 | 71 | ||
| ... | @@ -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; |
| 7 | const math = std.math; | 7 | const math = std.math; |
| 8 | const Xoshiro256 = @This(); | 8 | const Xoshiro256 = @This(); |
| 9 | 9 | ||
| 10 | random: Random, | ||
| 11 | |||
| 12 | s: [4]u64, | 10 | s: [4]u64, |
| 13 | 11 | ||
| 14 | pub fn init(init_s: u64) Xoshiro256 { | 12 | pub 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 | }; |
| 19 | 16 | ||
| ... | @@ -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 | } |
| 23 | 20 | ||
| 21 | pub fn random(self: *Xoshiro256) Random { | ||
| 22 | return Random.init(self); | ||
| 23 | } | ||
| 24 | |||
| 24 | fn next(self: *Xoshiro256) u64 { | 25 | fn 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]; |
| 26 | 27 | ||
| ... | @@ -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 | } |
| 66 | 67 | ||
| 67 | fn fill(r: *Random, buf: []u8) void { | 68 | pub 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); |
| 72 | 71 | ||
| ... | @@ -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"); |
| 13 | const math = std.math; | 13 | const math = std.math; |
| 14 | const Random = std.rand.Random; | 14 | const Random = std.rand.Random; |
| 15 | 15 | ||
| 16 | pub fn next_f64(random: *Random, comptime tables: ZigTable) f64 { | 16 | pub 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 by | 18 | // 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 symmetric | 61 | // whether the distribution is symmetric |
| 62 | is_symmetric: bool, | 62 | is_symmetric: bool, |
| 63 | // fallback calculation in the case we are in the 0 block | 63 | // 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 | }; |
| 66 | 66 | ||
| 67 | // zigNorInit | 67 | // 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; |
| 77 | 77 | ||
| ... | @@ -111,7 +111,7 @@ fn norm_f(x: f64) f64 { | ... | @@ -111,7 +111,7 @@ fn norm_f(x: f64) f64 { |
| 111 | fn norm_f_inv(y: f64) f64 { | 111 | fn 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 | } |
| 114 | fn norm_zero_case(random: *Random, u: f64) f64 { | 114 | fn 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; |
| 117 | 117 | ||
| ... | @@ -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; |
| 134 | 134 | ||
| 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 | } |
| 141 | 143 | ||
| ... | @@ -154,7 +156,7 @@ fn exp_f(x: f64) f64 { | ... | @@ -154,7 +156,7 @@ fn exp_f(x: f64) f64 { |
| 154 | fn exp_f_inv(y: f64) f64 { | 156 | fn exp_f_inv(y: f64) f64 { |
| 155 | return -math.ln(y); | 157 | return -math.ln(y); |
| 156 | } | 158 | } |
| 157 | fn exp_zero_case(random: *Random, _: f64) f64 { | 159 | fn 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 | } |
| 160 | 162 | ||
| ... | @@ -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; |
| 163 | 165 | ||
| 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 | } |
| 170 | 174 |
lib/std/sort.zig+3-2| ... | @@ -1328,16 +1328,17 @@ test "another sort case" { | ... | @@ -1328,16 +1328,17 @@ test "another sort case" { |
| 1328 | 1328 | ||
| 1329 | test "sort fuzz testing" { | 1329 | test "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 | } |
| 1337 | 1338 | ||
| 1338 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; | 1339 | var fixed_buffer_mem: [100 * 1024]u8 = undefined; |
| 1339 | 1340 | ||
| 1340 | fn fuzzTest(rng: *std.rand.Random) !void { | 1341 | fn 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); |