authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-03-30 01:36:04+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-03-30 01:50:58+13:00
log0fd0f6fd1f4b9e02cc33eac304b9f6db242cbb67
treedc06675959dce091f7fa58c138d4b567cf2ba87f
parent032fccf6151ff201ce4b8c7ab28ca460fed794c0

Rewrite Rand functions

We now use a generic Rand structure which abstracts the core functions from the backing engine. The old Mersenne Twister engine is removed and replaced instead with three alternatives: - Pcg32 - Xoroshiro128+ - Isaac64 These should provide sufficient coverage for most purposes, including a CSPRNG using Isaac64. Consumers of the library that do not care about the actual engine implementation should use DefaultPrng and DefaultCsprng.

7 files changed, 735 insertions(+), 830 deletions(-)

CMakeLists.txt+1-1
......@@ -509,7 +509,7 @@ set(ZIG_STD_FILES
509509 "os/windows/index.zig"
510510 "os/windows/util.zig"
511511 "os/zen.zig"
512 "rand.zig"
512 "rand/index.zig"
513513 "sort.zig"
514514 "special/bootstrap.zig"
515515 "special/bootstrap_lib.zig"
std/index.zig+2-2
......@@ -26,7 +26,7 @@ pub const math = @import("math/index.zig");
2626pub const mem = @import("mem.zig");
2727pub const net = @import("net.zig");
2828pub const os = @import("os/index.zig");
29pub const rand = @import("rand.zig");
29pub const rand = @import("rand/index.zig");
3030pub const sort = @import("sort.zig");
3131pub const unicode = @import("unicode.zig");
3232pub const zig = @import("zig/index.zig");
......@@ -58,7 +58,7 @@ test "std" {
5858 _ = @import("heap.zig");
5959 _ = @import("net.zig");
6060 _ = @import("os/index.zig");
61 _ = @import("rand.zig");
61 _ = @import("rand/index.zig");
6262 _ = @import("sort.zig");
6363 _ = @import("unicode.zig");
6464 _ = @import("zig/index.zig");
std/io_test.zig+3-3
......@@ -1,7 +1,7 @@
11const std = @import("index.zig");
22const io = std.io;
33const allocator = std.debug.global_allocator;
4const Rand = std.rand.Rand;
4const DefaultPrng = std.rand.DefaultPrng;
55const assert = std.debug.assert;
66const mem = std.mem;
77const os = std.os;
......@@ -9,8 +9,8 @@ const builtin = @import("builtin");
99
1010test "write a file, read it, then delete it" {
1111 var data: [1024]u8 = undefined;
12 var rng = Rand.init(1234);
13 rng.fillBytes(data[0..]);
12 var prng = DefaultPrng.init(1234);
13 prng.random.bytes(data[0..]);
1414 const tmp_file_name = "temp_test_file.txt";
1515 {
1616 var file = try os.File.openWrite(allocator, tmp_file_name);
std/rand.zig deleted-240
......@@ -1,240 +0,0 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const rand_test = @import("rand_test.zig");
5const mem = std.mem;
6const math = std.math;
7
8pub const MT19937_32 = MersenneTwister(
9 u32, 624, 397, 31,
10 0x9908B0DF,
11 11, 0xFFFFFFFF,
12 7, 0x9D2C5680,
13 15, 0xEFC60000,
14 18, 1812433253);
15
16pub const MT19937_64 = MersenneTwister(
17 u64, 312, 156, 31,
18 0xB5026F5AA96619E9,
19 29, 0x5555555555555555,
20 17, 0x71D67FFFEDA60000,
21 37, 0xFFF7EEE000000000,
22 43, 6364136223846793005);
23
24/// Use `init` to initialize this state.
25pub const Rand = struct {
26 const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32;
27
28 rng: Rng,
29
30 /// Initialize random state with the given seed.
31 pub fn init(seed: usize) Rand {
32 return Rand {
33 .rng = Rng.init(seed),
34 };
35 }
36
37 /// Get an integer or boolean with random bits.
38 pub fn scalar(r: &Rand, comptime T: type) T {
39 if (T == usize) {
40 return r.rng.get();
41 } else if (T == bool) {
42 return (r.rng.get() & 0b1) == 0;
43 } else {
44 var result: [@sizeOf(T)]u8 = undefined;
45 r.fillBytes(result[0..]);
46 return mem.readInt(result, T, builtin.Endian.Little);
47 }
48 }
49
50 /// Fill `buf` with randomness.
51 pub fn fillBytes(r: &Rand, buf: []u8) void {
52 var bytes_left = buf.len;
53 while (bytes_left >= @sizeOf(usize)) {
54 mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little);
55 bytes_left -= @sizeOf(usize);
56 }
57 if (bytes_left > 0) {
58 var rand_val_array: [@sizeOf(usize)]u8 = undefined;
59 mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little);
60 while (bytes_left > 0) {
61 buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
62 bytes_left -= 1;
63 }
64 }
65 }
66
67 /// Get a random unsigned integer with even distribution between `start`
68 /// inclusive and `end` exclusive.
69 pub fn range(r: &Rand, comptime T: type, start: T, end: T) T {
70 assert(start <= end);
71 if (T.is_signed) {
72 const uint = @IntType(false, T.bit_count);
73 if (start >= 0 and end >= 0) {
74 return T(r.range(uint, uint(start), uint(end)));
75 } else if (start < 0 and end < 0) {
76 // Can't overflow because the range is over signed ints
77 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
78 } else if (start < 0 and end >= 0) {
79 const end_uint = uint(end);
80 const total_range = math.absCast(start) + end_uint;
81 const value = r.range(uint, 0, total_range);
82 const result = if (value < end_uint) x: {
83 break :x T(value);
84 } else if (value == end_uint) x: {
85 break :x start;
86 } else x: {
87 // Can't overflow because the range is over signed ints
88 break :x math.negateCast(value - end_uint) catch unreachable;
89 };
90 return result;
91 } else {
92 unreachable;
93 }
94 } else {
95 const total_range = end - start;
96 const leftover = @maxValue(T) % total_range;
97 const upper_bound = @maxValue(T) - leftover;
98 var rand_val_array: [@sizeOf(T)]u8 = undefined;
99
100 while (true) {
101 r.fillBytes(rand_val_array[0..]);
102 const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
103 if (rand_val < upper_bound) {
104 return start + (rand_val % total_range);
105 }
106 }
107 }
108 }
109
110 /// Get a floating point value in the range 0.0..1.0.
111 pub fn float(r: &Rand, comptime T: type) T {
112 // TODO Implement this way instead:
113 // const int = @int_type(false, @sizeOf(T) * 8);
114 // const mask = ((1 << @float_mantissa_bit_count(T)) - 1);
115 // const rand_bits = r.rng.scalar(int) & mask;
116 // return @float_compose(T, false, 0, rand_bits) - 1.0
117 const int_type = @IntType(false, @sizeOf(T) * 8);
118 const precision = if (T == f32)
119 16777216
120 else if (T == f64)
121 9007199254740992
122 else
123 @compileError("unknown floating point type")
124 ;
125 return T(r.range(int_type, 0, precision)) / T(precision);
126 }
127};
128
129fn MersenneTwister(
130 comptime int: type, comptime n: usize, comptime m: usize, comptime r: int,
131 comptime a: int,
132 comptime u: math.Log2Int(int), comptime d: int,
133 comptime s: math.Log2Int(int), comptime b: int,
134 comptime t: math.Log2Int(int), comptime c: int,
135 comptime l: math.Log2Int(int), comptime f: int) type
136{
137 return struct {
138 const Self = this;
139
140 array: [n]int,
141 index: usize,
142
143 pub fn init(seed: int) Self {
144 var mt = Self {
145 .array = undefined,
146 .index = n,
147 };
148
149 var prev_value = seed;
150 mt.array[0] = prev_value;
151 var i: usize = 1;
152 while (i < n) : (i += 1) {
153 prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));
154 mt.array[i] = prev_value;
155 }
156 return mt;
157 }
158
159 pub fn get(mt: &Self) int {
160 const mag01 = []int{0, a};
161 const LM: int = (1 << r) - 1;
162 const UM = ~LM;
163
164 if (mt.index >= n) {
165 var i: usize = 0;
166
167 while (i < n - m) : (i += 1) {
168 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
169 mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
170 }
171
172 while (i < n - 1) : (i += 1) {
173 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
174 mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
175
176 }
177 const x = (mt.array[i] & UM) | (mt.array[0] & LM);
178 mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[usize(x & 0x1)];
179
180 mt.index = 0;
181 }
182
183 var x = mt.array[mt.index];
184 mt.index += 1;
185
186 x ^= ((x >> u) & d);
187 x ^= ((x << s) & b);
188 x ^= ((x << t) & c);
189 x ^= (x >> l);
190
191 return x;
192 }
193 };
194}
195
196test "rand float 32" {
197 var r = Rand.init(42);
198 var i: usize = 0;
199 while (i < 1000) : (i += 1) {
200 const val = r.float(f32);
201 assert(val >= 0.0);
202 assert(val < 1.0);
203 }
204}
205
206test "rand.MT19937_64" {
207 var rng = MT19937_64.init(rand_test.mt64_seed);
208 for (rand_test.mt64_data) |value| {
209 assert(value == rng.get());
210 }
211}
212
213test "rand.MT19937_32" {
214 var rng = MT19937_32.init(rand_test.mt32_seed);
215 for (rand_test.mt32_data) |value| {
216 assert(value == rng.get());
217 }
218}
219
220test "rand.Rand.range" {
221 var r = Rand.init(42);
222 testRange(&r, -4, 3);
223 testRange(&r, -4, -1);
224 testRange(&r, 10, 14);
225}
226
227fn testRange(r: &Rand, start: i32, end: i32) void {
228 const count = usize(end - start);
229 var values_buffer = []bool{false} ** 20;
230 const values = values_buffer[0..count];
231 var i: usize = 0;
232 while (i < count) {
233 const value = r.range(i32, start, end);
234 const index = usize(value - start);
235 if (!values[index]) {
236 i += 1;
237 values[index] = true;
238 }
239 }
240}
std/rand/index.zig created+652
......@@ -0,0 +1,652 @@
1// The engines provided here should be initialized from an external source. For now, getRandomBytes
2// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.
4//
5// ```
6// var buf: [8]u8 = undefined;
7// try std.os.getRandomBytes(buf[0..]);
8// const seed = mem.readInt(buf[0..8], u64, builtin.Endian.Little);
9//
10// var r = DefaultPrng.init(seed);
11//
12// const s = r.random.scalar(u64);
13// ```
14//
15// TODO(tiehuis): Benchmark these against other reference implementations.
16
17const std = @import("../index.zig");
18const builtin = @import("builtin");
19const assert = std.debug.assert;
20const mem = std.mem;
21const math = std.math;
22
23// When you need fast unbiased random numbers
24pub const DefaultPrng = Xoroshiro128;
25
26// When you need cryptographically secure random numbers
27pub const DefaultCsprng = Isaac64;
28
29pub const Rand = struct {
30 fillFn: fn(r: &Rand, buf: []u8) void,
31
32 /// Read random bytes into the specified buffer until fill.
33 pub fn bytes(r: &Rand, buf: []u8) void {
34 r.fillFn(r, buf);
35 }
36
37 /// Return a random integer/boolean type.
38 pub fn scalar(r: &Rand, comptime T: type) T {
39 var rand_bytes: [@sizeOf(T)]u8 = undefined;
40 r.bytes(rand_bytes[0..]);
41
42 if (T == bool) {
43 return rand_bytes[0] & 0b1 == 0;
44 } else {
45 // NOTE: Cannot @bitCast array to integer type.
46 return mem.readInt(rand_bytes, T, builtin.Endian.Little);
47 }
48 }
49
50 /// Get a random unsigned integer with even distribution between `start`
51 /// inclusive and `end` exclusive.
52 pub fn range(r: &Rand, comptime T: type, start: T, end: T) T {
53 assert(start <= end);
54 if (T.is_signed) {
55 const uint = @IntType(false, T.bit_count);
56 if (start >= 0 and end >= 0) {
57 return T(r.range(uint, uint(start), uint(end)));
58 } else if (start < 0 and end < 0) {
59 // Can't overflow because the range is over signed ints
60 return math.negateCast(r.range(uint, math.absCast(end), math.absCast(start)) + 1) catch unreachable;
61 } else if (start < 0 and end >= 0) {
62 const end_uint = uint(end);
63 const total_range = math.absCast(start) + end_uint;
64 const value = r.range(uint, 0, total_range);
65 const result = if (value < end_uint) x: {
66 break :x T(value);
67 } else if (value == end_uint) x: {
68 break :x start;
69 } else x: {
70 // Can't overflow because the range is over signed ints
71 break :x math.negateCast(value - end_uint) catch unreachable;
72 };
73 return result;
74 } else {
75 unreachable;
76 }
77 } else {
78 const total_range = end - start;
79 const leftover = @maxValue(T) % total_range;
80 const upper_bound = @maxValue(T) - leftover;
81 var rand_val_array: [@sizeOf(T)]u8 = undefined;
82
83 while (true) {
84 r.bytes(rand_val_array[0..]);
85 const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
86 if (rand_val < upper_bound) {
87 return start + (rand_val % total_range);
88 }
89 }
90 }
91 }
92
93 /// Return a floating point value evenly distributed in the range [0, 1).
94 pub fn float(r: &Rand, comptime T: type) T {
95 // Generate a uniform value between [1, 2) and scale down to [0, 1).
96 // Note: The lowest mantissa bit is always set to 0 so we only use half the available range.
97 switch (T) {
98 f32 => {
99 const s = r.scalar(u32);
100 const repr = (0x7f << 23) | (s >> 9);
101 return @bitCast(f32, repr) - 1.0;
102 },
103 f64 => {
104 const s = r.scalar(u64);
105 const repr = (0x3ff << 52) | (s >> 12);
106 return @bitCast(f64, repr) - 1.0;
107 },
108 else => @compileError("unknown floating point type"),
109 }
110 }
111
112 /// Return a floating point value normally distributed in the range [0, 1].
113 pub fn floatNorm(r: &Rand, comptime T: type) T {
114 // TODO(tiehuis): See https://www.doornik.com/research/ziggurat.pdf
115 @compileError("floatNorm is unimplemented");
116 }
117
118 /// Return a exponentially distributed float between (0, @maxValue(f64))
119 pub fn floatExp(r: &Rand, comptime T: type) T {
120 @compileError("floatExp is unimplemented");
121 }
122
123 /// Shuffle a slice into a random order.
124 pub fn shuffle(r: &Rand, comptime T: type, buf: []T) void {
125 if (buf.len < 2) {
126 return;
127 }
128
129 var i: usize = 0;
130 while (i < buf.len - 1) : (i += 1) {
131 const j = r.range(usize, i, buf.len);
132 mem.swap(T, &buf[i], &buf[j]);
133 }
134 }
135};
136
137// Generator to extend 64-bit seed values into longer sequences.
138//
139// The number of cycles is thus limited to 64-bits regardless of the engine, but this
140// is still plenty for practical purposes.
141const SplitMix64 = struct {
142 s: u64,
143
144 pub fn init(seed: u64) SplitMix64 {
145 return SplitMix64 { .s = seed };
146 }
147
148 pub fn next(self: &SplitMix64) u64 {
149 self.s +%= 0x9e3779b97f4a7c15;
150
151 var z = self.s;
152 z = (z ^ (z >> 30)) *% 0xbf58476d1ce4e5b9;
153 z = (z ^ (z >> 27)) *% 0x94d049bb133111eb;
154 return z ^ (z >> 31);
155 }
156};
157
158test "splitmix64 sequence" {
159 var r = SplitMix64.init(0xaeecf86f7878dd75);
160
161 const seq = []const u64 {
162 0x5dbd39db0178eb44,
163 0xa9900fb66b397da3,
164 0x5c1a28b1aeebcf5c,
165 0x64a963238f776912,
166 0xc6d4177b21d1c0ab,
167 0xb2cbdbdb5ea35394,
168 };
169
170 for (seq) |s| {
171 std.debug.assert(s == r.next());
172 }
173}
174
175// PCG32 - http://www.pcg-random.org/
176//
177// PRNG
178pub const Pcg = struct {
179 const default_multiplier = 6364136223846793005;
180
181 random: Rand,
182
183 s: u64,
184 i: u64,
185
186 pub fn init(init_s: u64) Pcg {
187 var pcg = Pcg {
188 .random = Rand { .fillFn = fill },
189 .s = undefined,
190 .i = undefined,
191 };
192
193 pcg.seed(init_s);
194 return pcg;
195 }
196
197 fn next(self: &Pcg) u32 {
198 const l = self.s;
199 self.s = l *% default_multiplier +% (self.i | 1);
200
201 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
202 const rot = u32(l >> 59);
203
204 return (xor_s >> u5(rot)) | (xor_s << u5((0 -% rot) & 31));
205 }
206
207 fn seed(self: &Pcg, init_s: u64) void {
208 // Pcg requires 128-bits of seed.
209 var gen = SplitMix64.init(init_s);
210 self.seedTwo(gen.next(), gen.next());
211 }
212
213 fn seedTwo(self: &Pcg, init_s: u64, init_i: u64) void {
214 self.s = 0;
215 self.i = (init_s << 1) | 1;
216 self.s = self.s *% default_multiplier +% self.i;
217 self.s +%= init_i;
218 self.s = self.s *% default_multiplier +% self.i;
219 }
220
221 fn fill(r: &Rand, buf: []u8) void {
222 const self = @fieldParentPtr(Pcg, "random", r);
223
224 var i: usize = 0;
225 const aligned_len = buf.len - (buf.len & 7);
226
227 // Complete 4 byte segments.
228 while (i < aligned_len) : (i += 4) {
229 var n = self.next();
230 comptime var j: usize = 0;
231 inline while (j < 4) : (j += 1) {
232 buf[i + j] = @truncate(u8, n);
233 n >>= 8;
234 }
235 }
236
237 // Remaining. (cuts the stream)
238 if (i != buf.len) {
239 var n = self.next();
240 while (i < buf.len) : (i += 1) {
241 buf[i] = @truncate(u8, n);
242 n >>= 4;
243 }
244 }
245 }
246};
247
248test "pcg sequence" {
249 var r = Pcg.init(0);
250 const s0: u64 = 0x9394bf54ce5d79de;
251 const s1: u64 = 0x84e9c579ef59bbf7;
252 r.seedTwo(s0, s1);
253
254 const seq = []const u32 {
255 2881561918,
256 3063928540,
257 1199791034,
258 2487695858,
259 1479648952,
260 3247963454,
261 };
262
263 for (seq) |s| {
264 std.debug.assert(s == r.next());
265 }
266}
267
268// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
269//
270// PRNG
271pub const Xoroshiro128 = struct {
272 random: Rand,
273
274 s: [2]u64,
275
276 pub fn init(init_s: u64) Xoroshiro128 {
277 var x = Xoroshiro128 {
278 .random = Rand { .fillFn = fill },
279 .s = undefined,
280 };
281
282 x.seed(init_s);
283 return x;
284 }
285
286 fn next(self: &Xoroshiro128) u64 {
287 const s0 = self.s[0];
288 var s1 = self.s[1];
289 const r = s0 +% s1;
290
291 s1 ^= s0;
292 self.s[0] = math.rotl(u64, s0, u8(55)) ^ s1 ^ (s1 << 14);
293 self.s[1] = math.rotl(u64, s1, u8(36));
294
295 return r;
296 }
297
298 // Skip 2^64 places ahead in the sequence
299 fn jump(self: &Xoroshiro128) void {
300 var s0: u64 = 0;
301 var s1: u64 = 0;
302
303 const table = []const u64 {
304 0xbeac0467eba5facb,
305 0xd86b048b86aa9922
306 };
307
308 inline for (table) |entry| {
309 var b: usize = 0;
310 while (b < 64) : (b += 1) {
311 if ((entry & (u64(1) << u6(b))) != 0) {
312 s0 ^= self.s[0];
313 s1 ^= self.s[1];
314 }
315 _ = self.next();
316 }
317 }
318
319 self.s[0] = s0;
320 self.s[1] = s1;
321 }
322
323 fn seed(self: &Xoroshiro128, init_s: u64) void {
324 // Xoroshiro requires 128-bits of seed.
325 var gen = SplitMix64.init(init_s);
326
327 self.s[0] = gen.next();
328 self.s[1] = gen.next();
329 }
330
331 fn fill(r: &Rand, buf: []u8) void {
332 const self = @fieldParentPtr(Xoroshiro128, "random", r);
333
334 var i: usize = 0;
335 const aligned_len = buf.len - (buf.len & 7);
336
337 // Complete 8 byte segments.
338 while (i < aligned_len) : (i += 8) {
339 var n = self.next();
340 comptime var j: usize = 0;
341 inline while (j < 8) : (j += 1) {
342 buf[i + j] = @truncate(u8, n);
343 n >>= 8;
344 }
345 }
346
347 // Remaining. (cuts the stream)
348 if (i != buf.len) {
349 var n = self.next();
350 while (i < buf.len) : (i += 1) {
351 buf[i] = @truncate(u8, n);
352 n >>= 8;
353 }
354 }
355 }
356};
357
358test "xoroshiro sequence" {
359 var r = Xoroshiro128.init(0);
360 r.s[0] = 0xaeecf86f7878dd75;
361 r.s[1] = 0x01cd153642e72622;
362
363 const seq1 = []const u64 {
364 0xb0ba0da5bb600397,
365 0x18a08afde614dccc,
366 0xa2635b956a31b929,
367 0xabe633c971efa045,
368 0x9ac19f9706ca3cac,
369 0xf62b426578c1e3fb,
370 };
371
372 for (seq1) |s| {
373 std.debug.assert(s == r.next());
374 }
375
376
377 r.jump();
378
379 const seq2 = []const u64 {
380 0x95344a13556d3e22,
381 0xb4fb32dafa4d00df,
382 0xb2011d9ccdcfe2dd,
383 0x05679a9b2119b908,
384 0xa860a1da7c9cd8a0,
385 0x658a96efe3f86550,
386 };
387
388 for (seq2) |s| {
389 std.debug.assert(s == r.next());
390 }
391}
392
393// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
394//
395// CSPRNG
396//
397// Follows the general idea of the implementation from here with a few shortcuts.
398// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
399pub const Isaac64 = struct {
400 random: Rand,
401
402 r: [256]u64,
403 m: [256]u64,
404 a: u64,
405 b: u64,
406 c: u64,
407 i: usize,
408
409 pub fn init(init_s: u64) Isaac64 {
410 var isaac = Isaac64 {
411 .random = Rand { .fillFn = fill },
412 .r = undefined,
413 .m = undefined,
414 .a = undefined,
415 .b = undefined,
416 .c = undefined,
417 .i = undefined,
418 };
419
420 // seed == 0 => same result as the unseeded reference implementation
421 isaac.seed(init_s, 1);
422 return isaac;
423 }
424
425 fn step(self: &Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
426 const x = self.m[base + m1];
427 self.a = mix +% self.m[base + m2];
428
429 const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len];
430 self.m[base + m1] = y;
431
432 self.b = x +% self.m[(y >> 11) % self.m.len];
433 self.r[self.r.len - 1 - base - m1] = self.b;
434 }
435
436 fn refill(self: &Isaac64) void {
437 const midpoint = self.r.len / 2;
438
439 self.c +%= 1;
440 self.b +%= self.c;
441
442 {
443 var i: usize = 0;
444 while (i < midpoint) : (i += 4) {
445 self.step( ~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
446 self.step( self.a ^ (self.a >> 5) , i + 1, 0, midpoint);
447 self.step( self.a ^ (self.a << 12) , i + 2, 0, midpoint);
448 self.step( self.a ^ (self.a >> 33) , i + 3, 0, midpoint);
449 }
450 }
451
452 {
453 var i: usize = 0;
454 while (i < midpoint) : (i += 4) {
455 self.step( ~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
456 self.step( self.a ^ (self.a >> 5) , i + 1, midpoint, 0);
457 self.step( self.a ^ (self.a << 12) , i + 2, midpoint, 0);
458 self.step( self.a ^ (self.a >> 33) , i + 3, midpoint, 0);
459 }
460 }
461
462 self.i = 0;
463 }
464
465 fn next(self: &Isaac64) u64 {
466 if (self.i >= self.r.len) {
467 self.refill();
468 }
469
470 const value = self.r[self.i];
471 self.i += 1;
472 return value;
473 }
474
475 fn seed(self: &Isaac64, init_s: u64, comptime rounds: usize) void {
476 // We ignore the multi-pass requirement since we don't currently expose full access to
477 // seeding the self.m array completely.
478 mem.set(u64, self.m[0..], 0);
479 self.m[0] = init_s;
480
481 // prescrambled golden ratio constants
482 var a = []const u64 {
483 0x647c4677a2884b7c,
484 0xb9f8b322c73ac862,
485 0x8c0ea5053d4712a0,
486 0xb29b2e824a595524,
487 0x82f053db8355e0ce,
488 0x48fe4a0fa5a09315,
489 0xae985bf2cbfc89ed,
490 0x98f5704f6c44c0ab,
491 };
492
493 comptime var i: usize = 0;
494 inline while (i < rounds) : (i += 1) {
495 var j: usize = 0;
496 while (j < self.m.len) : (j += 8) {
497 comptime var x1: usize = 0;
498 inline while (x1 < 8) : (x1 += 1) {
499 a[x1] +%= self.m[j + x1];
500 }
501
502 a[0] -%= a[4]; a[5] ^= a[7] >> 9; a[7] +%= a[0];
503 a[1] -%= a[5]; a[6] ^= a[0] << 9; a[0] +%= a[1];
504 a[2] -%= a[6]; a[7] ^= a[1] >> 23; a[1] +%= a[2];
505 a[3] -%= a[7]; a[0] ^= a[2] << 15; a[2] +%= a[3];
506 a[4] -%= a[0]; a[1] ^= a[3] >> 14; a[3] +%= a[4];
507 a[5] -%= a[1]; a[2] ^= a[4] << 20; a[4] +%= a[5];
508 a[6] -%= a[2]; a[3] ^= a[5] >> 17; a[5] +%= a[6];
509 a[7] -%= a[3]; a[4] ^= a[6] << 14; a[6] +%= a[7];
510
511 comptime var x2: usize = 0;
512 inline while (x2 < 8) : (x2 += 1) {
513 self.m[j + x2] = a[x2];
514 }
515 }
516 }
517
518 mem.set(u64, self.r[0..], 0);
519 self.a = 0;
520 self.b = 0;
521 self.c = 0;
522 self.i = self.r.len; // trigger refill on first value
523 }
524
525 fn fill(r: &Rand, buf: []u8) void {
526 const self = @fieldParentPtr(Isaac64, "random", r);
527
528 var i: usize = 0;
529 const aligned_len = buf.len - (buf.len & 7);
530
531 // Fill complete 64-byte segments
532 while (i < aligned_len) : (i += 8) {
533 var n = self.next();
534 comptime var j: usize = 0;
535 inline while (j < 8) : (j += 1) {
536 buf[i + j] = @truncate(u8, n);
537 n >>= 8;
538 }
539 }
540
541 // Fill trailing, ignoring excess (cut the stream).
542 if (i != buf.len) {
543 var n = self.next();
544 while (i < buf.len) : (i += 1) {
545 buf[i] = @truncate(u8, n);
546 n >>= 8;
547 }
548 }
549 }
550};
551
552test "isaac64 sequence" {
553 var r = Isaac64.init(0);
554
555 // from reference implementation
556 const seq = []const u64 {
557 0xf67dfba498e4937c,
558 0x84a5066a9204f380,
559 0xfee34bd5f5514dbb,
560 0x4d1664739b8f80d6,
561 0x8607459ab52a14aa,
562 0x0e78bc5a98529e49,
563 0xfe5332822ad13777,
564 0x556c27525e33d01a,
565 0x08643ca615f3149f,
566 0xd0771faf3cb04714,
567 0x30e86f68a37b008d,
568 0x3074ebc0488a3adf,
569 0x270645ea7a2790bc,
570 0x5601a0a8d3763c6a,
571 0x2f83071f53f325dd,
572 0xb9090f3d42d2d2ea,
573 };
574
575 for (seq) |s| {
576 std.debug.assert(s == r.next());
577 }
578}
579
580// Actual Rand helper function tests, pcg engine is assumed correct.
581test "Rand float" {
582 var prng = DefaultPrng.init(0);
583
584 var i: usize = 0;
585 while (i < 1000) : (i += 1) {
586 const val1 = prng.random.float(f32);
587 std.debug.assert(val1 >= 0.0);
588 std.debug.assert(val1 < 1.0);
589
590 const val2 = prng.random.float(f64);
591 std.debug.assert(val2 >= 0.0);
592 std.debug.assert(val2 < 1.0);
593 }
594}
595
596test "Rand scalar" {
597 var prng = DefaultPrng.init(0);
598 const s = prng .random.scalar(u64);
599}
600
601test "Rand bytes" {
602 var prng = DefaultPrng.init(0);
603 var buf: [2048]u8 = undefined;
604 prng.random.bytes(buf[0..]);
605}
606
607test "Rand shuffle" {
608 var prng = DefaultPrng.init(0);
609
610 var seq = []const u8 { 0, 1, 2, 3, 4 };
611 var seen = []bool {false} ** 5;
612
613 var i: usize = 0;
614 while (i < 1000) : (i += 1) {
615 prng.random.shuffle(u8, seq[0..]);
616 seen[seq[0]] = true;
617 std.debug.assert(sumArray(seq[0..]) == 10);
618 }
619
620 // we should see every entry at the head at least once
621 for (seen) |e| {
622 std.debug.assert(e == true);
623 }
624}
625
626fn sumArray(s: []const u8) u32 {
627 var r: u32 = 0;
628 for (s) |e| r += e;
629 return r;
630}
631
632test "Rand range" {
633 var prng = DefaultPrng.init(0);
634 testRange(&prng.random, -4, 3);
635 testRange(&prng.random, -4, -1);
636 testRange(&prng.random, 10, 14);
637}
638
639fn testRange(r: &Rand, start: i32, end: i32) void {
640 const count = usize(end - start);
641 var values_buffer = []bool{false} ** 20;
642 const values = values_buffer[0..count];
643 var i: usize = 0;
644 while (i < count) {
645 const value = r.range(i32, start, end);
646 const index = usize(value - start);
647 if (!values[index]) {
648 i += 1;
649 values[index] = true;
650 }
651 }
652}
std/rand_test.zig deleted-507
......@@ -1,507 +0,0 @@
1pub const mt64_seed = 0xb334e49d0977c37e;
2pub const mt64_data = []u64 {
3 0x2ad1a63fab6d25a9, 0xb7143aba12569814, 0xc1b60d8d49e53e8, 0x5652adfc8da656dc,
4 0x43e3beb6d9e484a9, 0x17b09b71e9418ff7, 0x541646292686cfa4, 0x260457071268ecfc,
5 0x1627af31774e1dc1, 0x362a49b34ed75bb3, 0x7acf72002fe0f733, 0x3aaaf2e7b9409452,
6 0x9cfc2d9908115c2, 0x6e81a7f16ae613e9, 0xfc4da89c04acf3c7, 0x6984b6adb4feb9ae,
7 0x6a128b334e27b03d, 0xcc45a2b02937871a, 0xe585b229e00b2283, 0x7a92c0664a6f678a,
8 0x972735011bdc0744, 0xb494e743d658a084, 0x1eda3c4e7b1b2d0c, 0x4c7adb3831d87332,
9 0x12f8c7355f5ec631, 0xfc2bcb6be7d60eba, 0x74b95b47895f8687, 0x171de6fe92b97f5a,
10 0x86383730f52719ac, 0xe4e43ce0f61274f6, 0x514f7e072d96f19c, 0xabef324fbc6cb7fe,
11 0x7534b945b742f14f, 0x47f9efe33265adbe, 0x7bcab027a0abf16b, 0x3312a2b34225bff7,
12 0xb61455ce8c2e3e0b, 0x2b81008deeee4d94, 0x743b0b2b4974c7b6, 0xfc219101fd665f7d,
13 0x863d78891cbfe5e5, 0x7531bb1839181778, 0xf614359a65356e72, 0xfcdd1f6e3f250bdd,
14 0x528e10bd536eed5b, 0x9f69386ac60cd618, 0xbf5f242706817f01, 0x8e7da8070072cf64,
15 0xaa318b622da0667f, 0xc9580540fb7efd66, 0xb5d996deccd02e0e, 0x81c6a799ea3f5a41,
16 0xe6b896f4e21a8550, 0xde5206f177a24ceb, 0x53343e81639ec0b6, 0x5a6edb63d08be9f6,
17 0x3602c2892f7da1b9, 0xda84f4259841bdea, 0x5880e169a7746e45, 0x57cddb5ffd3c2423,
18 0x28fe1166fe7b8595, 0x92136c9decb42243, 0xa8c4199818ca7d62, 0x5042cd96f62854dd,
19 0x22b2d38c3f21f8d0, 0x73a2bfccf1b5f7bb, 0xaba3718f40b6984e, 0x9c1f5dc3e399f5f0,
20 0x9cf463f95369c149, 0xa7546d69e4232e18, 0x9ea57317d19ab7fc, 0xfb13c83d830731fb,
21 0x635a123eaa099259, 0x9a2fe7d0ba6e3c5c, 0x40b903cd0d0d3b4e, 0xc8210eb2d2e941cb,
22 0xd2582d4b1e016484, 0x1d048030875af39c, 0xb51c31a6c193d76f, 0x5ce9b801b8d61626,
23 0x2bae30455cbb0022, 0xba54df5998b2443f, 0x927abb9342c9a90a, 0xc431eb7df3e06727,
24 0x726f885d3da88d5, 0x7d85ff1ca4260280, 0xaf3fecf8f019817, 0x31d39105d6fc4fe8,
25 0x262d9842dbafd4bd, 0x54c28a2876e62e39, 0x95a986e24e214dde, 0xbf677a1abd2e553,
26 0x48ac890ff787b2b6, 0x2890ec1c67c539f4, 0x7ce88bf3975882c3, 0x88ef340414a29c88,
27 0xe30de9c88a00805b, 0xe772225e3ee6c68a, 0xa3a7d0921c5d5816, 0x8354957227b1663f,
28 0xb5b65ded7c747cbc, 0x93b4a12ff2e8fcea, 0x6359579c3c438b3c, 0x45b2c12e9722f2bd,
29 0x659a604414f19e1, 0x4ec9a149d4219ca5, 0xd830290dd6aebe2b, 0xabc7874a6b4827f8,
30 0xc91be5dd875847e7, 0x5b761d39f3f96aee, 0x5749dffad692b6c8, 0x86c94840cbd249d2,
31 0x411a466e886ad7, 0x27dca1f51aebb9a0, 0x1cceb093fbab7a42, 0x7140c2d6706e927c,
32 0x6881fdb87299a92f, 0xa81a28de171f3c47, 0x8fa9a1b3bb5dfb2a, 0xae076853e3e0abde,
33 0xe76572308ecd6b54, 0x6cd926c2e2760d8a, 0xdf080266cfbe3dc3, 0xb99b961999765d7b,
34 0xadb5d4e2b896ddf1, 0x8d3aaf4c83c83c56, 0x9b66e4f6eb65bef7, 0x7a81c3bf785eb1df,
35 0xc53f02b3e8c38647, 0xcdfeb25ee787759d, 0xead5e734d64ab5f6, 0x7930d87af1072499,
36 0xf30690a71d88ad6e, 0x73c347923c84728a, 0x3f2b588221003fe4, 0xe747052d0b453af2,
37 0xabe6fa70539b5edf, 0x4db6d1530d628c2, 0x4ec929af434eb1b0, 0x15afbe39886181ff,
38 0xa9141b9c89a07b80, 0x7d33f966c6232057, 0x8ddcb412f34a491d, 0xa74472b8ecc1e2f2,
39 0x34d745de1cb7de2e, 0x6cf67091309e5e93, 0xfb25004efa59450a, 0x3355947066522286,
40 0x5a8cffdf079dac21, 0x419445d6e6825887, 0x6e9c064f84381dcf, 0xbbcaf462a3a8ad76,
41 0x75836c68d6c1a13e, 0xf38141565d5c3759, 0x8c65989142ffa802, 0x106067ec26e6463,
42 0xadfac5e3a80de9c2, 0xc48b16e2df25b9f2, 0xa3257889c33669e6, 0x5bc760d4d65a1745,
43 0x303cd31fead81139, 0xfb97f78cade31e1d, 0xb888b8e05820a469, 0x7ebb8e44d47f54d9,
44 0xce76cdbb5ecdc529, 0xb1eb29949a099d52, 0xb6affc1b240a7eb3, 0x22977eac542906f1,
45 0x9b105b391ff729df, 0x83371186b2834968, 0xd5b893f382ea9e90, 0x5d17aa80a1fd4854,
46 0xe8ed8525eb29210c, 0xc789f3cd36c4dae3, 0x556e50a5f46b73fb, 0xef1d129b523dff77,
47 0x851de0f53f6707f9, 0x8deeeadfb1fa8bfc, 0x3d8c89c0e08c4f2e, 0xecfaaea537123333,
48 0x5bc9053d2dfd7669, 0x408c5bb2e880a9a2, 0x495726b3f3248219, 0x2b23cca4a6ea1ccc,
49 0x1df3663045092d61, 0xaf977a46e965e45b, 0x43a2facfff7f97e, 0x9b7714344c7b51e,
50 0x35643b24efb0559a, 0x502820785dc1af13, 0xbf82d2775b46433d, 0x1db626f2e16ca66,
51 0x744b031447c1e27d, 0x99e79898612f4606, 0xda02a728d234821f, 0xcf00c6fbb637a6e9,
52 0x242f2963196fd8b, 0x7aed8efc2dd562bb, 0x6204fb5d3dc6208a, 0x3e84861182fc7f6,
53 0xd14c4ee5aeef5c7a, 0x3749fbef94378dc1, 0x8fe710ec5cfc8566, 0xf43d7e495d5384d7,
54 0x8ff6396f1f1ce7c4, 0xf1252a6b6f86b42c, 0xddbbd098d6dca83f, 0x4e228724a227232a,
55 0x92a5a52ba2b24fa8, 0xdfc172b03fde669c, 0x34ee55adf7f0711c, 0x21d181e79b8000bc,
56 0xc788b1f48b37b693, 0x544fc4cfed0e0f92, 0xafca0c6de41789cc, 0xbb37bb5107ef97f8,
57 0xb9d62bf1dc0f6c95, 0xc78b5a36110dfb1, 0x1d615b658f39657e, 0x2bb2cd04cabcc360,
58 0xe563488ece6362f0, 0x213b56ce006fecc6, 0xc38207089fed0270, 0xa33199ff4a51d095,
59 0x1802ad28fb1896b1, 0xbead8f18c164a332, 0xceb5149101aa450f, 0x39ad89851ee8b62a,
60 0x317229aafabf37c4, 0xee68b8b9bf3520b3, 0xe4db499288350f04, 0xf8ea27feddb0ae7a,
61 0xa17235067b489c42, 0xbf4a570245f95d78, 0x8065c67e1d1537ab, 0xbd9357fb1b30aee5,
62 0xc224166ebeb24c42, 0xf9baf8ccd01b53bf, 0x5c13775c3fea8038, 0x4ea66f6d650ce62d,
63 0x470592ed81c140f2, 0xc2d0eb6f7999321f, 0x85d762f20290dc0c, 0x9f7d0d13936f6e78,
64 0x41f1fd2d20f2d62d, 0x891cb19ce1af2c2f, 0xe7ff34c3b29c3719, 0x246743f43126c69c,
65 0xea4b2da3195ebab9, 0x4831e4de995187dc, 0x7fb8969bbee45ce5, 0xe35b483da73c44ed,
66 0xf89158ca9af36227, 0x9fc7f34a35469a7a, 0xd02483ebca6564e7, 0xca00da156aaeda03,
67 0x303d1514646822f1, 0x226832ae582b8eac, 0xf772d719e413504e, 0x87603b928c068ab1,
68 0x4dc1552230e9b883, 0xef8c5e9db946fc87, 0x935581290bf7a4ee, 0xca632d2c7674bf2,
69 0xd8a3933b80d39efd, 0xf026574d0ffee6fb, 0xe4412d0dcd2fe94f, 0x668916490a2983ec,
70 0x73b1fe84a995718, 0x729bedefe21cc0e7, 0xd3a770f1c683b98f, 0x5d597a96323a10c2,
71 0xfbb7834bbf5fed23, 0xf3546c805a42ccdd, 0x9ef3e2164bb31a0c, 0x388363ce6c6c2253,
72 0x8120f4a949f017cb, 0x925a61942bbd3d10, 0xa03182d8599c0521, 0x2412e23004b40ebb,
73 0x35010a126bf2aecc, 0x21147869a1a84ca7, 0x53cba503b6127b98, 0x10c89dd62ab3591c,
74 0xf4c7f84faaf9f5f1, 0x8b4a37a2e844b97b, 0x23ddeb236a0bd9af, 0x4fd51d7207f49e62,
75 0x6cdab447c27706b2, 0x9e8f54b9a2d1a790, 0x191aed85d4d77087, 0xf74ecf5015265af6,
76 0x45925e25404922a1, 0xcf5467a0f5b42b98, 0x73590809c85c728c, 0xc16beeda74a1a1b8,
77 0xc3bbe7999803dd6a, 0x1a368bb32eec184, 0xafad2d86b7bb574f, 0xdc7c7b8960dc921a,
78 0xd9b68d854f5e0ae1, 0xe9e1a6a16efe0bea, 0x304a15bd6ca1cb14, 0x713ce3144e0af4b9,
79 0xc50eb410981be1d2, 0xb0fba6119bf7a300, 0x7a107296731fd314, 0xdd764898a90042b3,
80 0x8a69973262da3bc8, 0x29c6b9d048596c44, 0x62581bd20da76f1b, 0x4d1a3941d6d3e4bb,
81 0x19c447306245055, 0xb2978afcd04ba357, 0x7c01cdefcfe24432, 0xc4b268314411deae,
82 0x5ba56d49da714765, 0x33299186ac6dfd09, 0xede087aec096ef0d, 0xf758da2c7bcf9ddb,
83 0x5ea6c40d56824cdd, 0x121ff879d6ba905b, 0xb5fed0c42b616f5c, 0x21029cdc347de152,
84 0xb251d93f4cd7bf4a, 0xaedcb2dc6402cf13, 0x840e5e0d96e89407, 0x6a92fd328efcc6ef,
85 0xc63f5d8f6fcadcbd, 0x405bd64d1621128e, 0xe1318888172f58ed, 0x1009c9764d49da2b,
86 0x4bc0592cbfdf9f91, 0x972f0e080dfecd02, 0xa1cb961958eeb6aa, 0x6ee6467ad8c20aca,
87 0xb3f1c738390d6a83, 0x6504eb7ac498650d, 0xdf7dda67f198f59f, 0x72615652e56a82c3,
88 0x85e0fa2dfb51755a, 0x98b1f92a3d2ad940, 0xce81d51d875c0045, 0x437004d0be0a4d69,
89 0x64065895526f896c, 0xe1e1fea920785d49, 0x7d507ffd56fda19a, 0x17309b625cecb42,
90 0x67b6d83f0fd0f572, 0x5178665a5bcd38f4, 0x3c49fda2d35a8606, 0x7f058d2cb0ad351c,
91 0xfb95691559245416, 0xc991b857662b1b9f, 0x9e6d0f4e19774f96, 0x26cc7502212ca578,
92 0x3466110f03225e49, 0x2ae4958375eab9f3, 0x939a8d94c8871191, 0xa27356548ac6b28d,
93 0xacf86d43ec3aa030, 0xe0d16c7fa0b13a8c, 0x408ec2b2f8da531b, 0xde72494115ee4e83,
94 0xd26d7f79a02c5b1e, 0x2b6f835520c97f6a, 0x1f30f008b109ae7d, 0x698dbf9acaa222f1,
95 0xbd55de40838376d5, 0xebe53822cec7eb80, 0x7ce900793008d2bc, 0x494fc7d10e8331bb,
96 0x53509b90bdb7d588, 0x62aa920e9554b2f2, 0xe103098542011b6f, 0xeb722b9523d68af8,
97 0xb71b1a6ea2c6591b, 0x97cd7da55c940270, 0x8ab70184427e45dc, 0x6cb6907427808465,
98 0xf69232a42dbe7475, 0xbc9816d429fa8909, 0xef1e74244539d41b, 0x5569b6d10440d5c,
99 0x7dda6817985c8ef5, 0xb270ed19cc8161b3, 0x87d80b66c8a15db0, 0x96966684c3ba47fb,
100 0x996669bc87aff3bf, 0x17c015383c793f2, 0xa4b5de41fc69f61a, 0x14a0eb4e3055742f,
101 0x5f0da5a7a2b8bc79, 0x5fe0353728aac023, 0x1554daf4abe92eed, 0x545722dac774b6a4,
102 0x733fc54174f2e0d1, 0x3478ef85dd994316, 0x58ba2ac090ef7575, 0xa66b9b0cbc77b6e2,
103 0xdc78cab5c708a3ee, 0x97a30c27be510f61, 0xb95d0b06fc0910b6, 0xdc80bdc42f79a25f,
104 0x5cadc438e65b3070, 0x6263df49ce691b9c, 0xa7ce160daa64416b, 0xa4f8bfedb57288c1,
105 0xa51714e187bbcfe9, 0xe25df4e9fc44644c, 0xeaf1854b3116ce11, 0xde1b8f810991a604,
106 0xd4fc2e365e99be4b, 0x8d1b0d2799527e06, 0x7cac59eaf46baba, 0x4fa63c74d2dabaf1,
107 0x4f6c5d5e676733a6, 0x7ab7ddb9c1b789b7, 0x5d9beb4877a37034, 0x5e96bc9de3985bcb,
108 0x72bab4dcb75b3228, 0xfa40f33c4d799e1f, 0x73e6f61a69984a6b, 0x7499c9af466cf22f,
109 0x42fab9136bfa64dd, 0xd5e8e39513b6fffd, 0x8eda1fd5ad8cd51d, 0x95338744859dff44,
110 0x4f0c5e5ae768c729, 0x5bc92c60495ae348, 0xcbb48c170ac21168, 0x8374aa2440eeb138,
111 0x70b663d6f6d70ca9, 0x11264ca6dd79e5a0, 0xf058a2c156974514, 0x36820eefc435ba63,
112 0xd7b69f3d0c0c27a1, 0xe1a2eddf3b41d205, 0x80508ec93b038bc8, 0xd7e0429bd511ff37,
113 0x7bf55a4e87e183b8, 0x4cb370ce7edb4bea, 0x26fbd0b31dcef45b, 0xf7acbd6781419fa6,
114 0xf7849659f05c90c, 0xb686271ea57a47c6, 0x16f3f839dbfb4e1b, 0x906872b08b2c61a,
115 0xc30c86d0a0203c15, 0xdaf238a6aa4fc9f7, 0x2399aa09ad2c069a, 0xf133c3aca703f545,
116 0x868a10304a1c98ba, 0x60ef0607f46f7e90, 0xe4e69f26931e11a5, 0x487b8f6bd6d92941,
117 0xd10cb2971798c0c7, 0x7126d81aa4bd0106, 0xcb620311dc84ab82, 0x26f8734a7a356bb2,
118 0xcf9b9eeb02ee978c, 0x8a9ff0285d4d6b30, 0xe30e3b957e2cc7f8, 0x7c15a09e4d275809,
119 0xdf723ae1dda5d167, 0xac212e4f6264bba2, 0xe3d60920ed983308, 0x91b403cbc91e290c,
120 0xcdb905b012aff7c7, 0xb5ee73d45f900897, 0xafacc7cd7f5d52e7, 0xa8653272621165d6,
121 0x90e2efc485ddd0d1, 0x56ef1ca9097b1a96, 0xc7a20f85777eb0a, 0xf4cec0271a50eae9,
122 0x21acd76442024973, 0x19a46be82a4abdbe, 0x1bc12e0b8bf41fbb, 0x3766fe3d8e5119f2,
123 0x7fea355c4c18e8ad, 0xd08b496a24fb8017, 0xe1a7cfaa0877aa2, 0xd37ad9e2a2a3fa96,
124 0xaa362ba0e696f679, 0x7e7de89142c3aca5, 0x2dedb0842a3575b8, 0xb74c1e1d9082fe5b,
125 0xb1ae74323699140f, 0x73623f80c727a6ea, 0x132ed204b0f10441, 0xc3e6ebe8ffc252bf,
126 0x5f15cffb8286dce0, 0x66dab32df780fa8f, 0xeb00da7b25ea99e4, 0x113ad2448fafb671,
127 0xee065c10a8f1924f, 0x2fcb7367cc01fe5, 0x484338f5c2d0aacd, 0xecfacd785e42d7a6,
128 0x11513f845de8af3a, 0xd11be6b29054de0d, 0x2536e5d2856af9b7, 0x60ab519760acd4c4,
129 0x6bfe010250a831ac, 0xb28a93e44b53b21b, 0x281cf9b233858583, 0x4ca6139abc79a710,
130 0x5717d33616d77a95, 0x9ba52d2b7dfe71b5, 0x32e1c543476aa17d, 0xae242cc75806b7fa,
131 0xa1415cb8fde770da, 0x3956c67542dc004d, 0x3a6f51518fdd20ce, 0x448c848f6c936d93,
132 0x8fec38ff51bb5fab, 0x7463816cfc0754ac, 0x83b38e531ba39e73, 0xf9fc84dcf4f8c93e,
133 0xdf20dbe8b91c3d6f, 0xec65939ac9516f9a, 0x888346f6c1aaa94a, 0xe42cabb108f60d95,
134 0x39bb2e46b0599fa9, 0x529335ed75acba9e, 0x6a8767c5d00776c4, 0x8243346104fe61a5,
135 0x7a2bd0339b3e9bac, 0xb68ccdf14473f4ba, 0xa06f389531ab553a, 0xc7c6f074fc2882d3,
136 0x50a5fd6e6d0df962, 0xd7c0000d194139b7, 0x5ae27ef4033f873d, 0x4e7abe8a6d3570f8,
137 0x27011ccd3885e709, 0x3dae53f7b7a8924a, 0xa9086c9b2b86fb71, 0xa3f9e534a399e62c,
138 0x9f2f0379f9a33ec6, 0xceb51af95d4472bd, 0x15aa534182f8465, 0x96373b9cd28a627b,
139 0x9fdce0ad99d41907, 0x2755bb0f52b8c239, 0x2f2e241b6aa7d243, 0xf040afbacb2f6001,
140 0x552267c5f8b4c1b0, 0x22bfb3f0b58f9e48, 0x6bff8de368dbee3a, 0x652025c63d4069ce,
141 0x743eb697b25f9c90, 0x8a3742c9dbf67b1c, 0xaf3bcfc260d7e69, 0x491facaa59b7e1d,
142 0xd07d0761e6535fcd, 0x79ef09d9d3859232, 0xe0e0a013317d9207, 0x4b94baecf6fe4b4e,
143 0x574576ed054cfc38, 0x90e90edd1a26f0aa, 0x616d32a371af78c6, 0x392cea9c34ffb0a8,
144 0x692a6e730c33ac6f, 0x9e4b92ef425b78a6, 0x291d4c962d2f3e7c, 0x5f0f8ebb67f308fc,
145 0xc1a0faf70ec747a3, 0x641da9550cd89392, 0x6adbe38115f09648, 0x3a51980fb324da0d,
146 0xee894f2b5c17a380, 0x58788fa693f767c9, 0xc9f490ff5d88c4c0, 0x2ca6e8b204aa3070,
147 0x7693837d7910c40c, 0x9240e04f16051720, 0xab773072d922faa2, 0xacb6892db8362872,
148 0x5ac8b4d130613c0e, 0x65cd5ac259c653cb, 0x9647e0276864f3f8, 0xe207c57ee9237a53,
149 0xe41f2663482a8fdb, 0xf605931fce8b95bd, 0x5b0247a9009255d2, 0xae949df3ab5a4ab5,
150 0xc0e912dacbb72c42, 0x4226971e6351f33a, 0xd98d41f9f0fdb6c3, 0x64bf6a0af66782d5,
151 0xb4ca689b3959bf46, 0xb4cbf621b4970922, 0xe9f27469c2412fe6, 0xb529d406d27c785e,
152 0xf33be21f2672ec78, 0x34b3c4c4603656cd, 0x4a7efe099a0ae9d1, 0xa6ad5b909667945b,
153 0xe20850e47ab440f7, 0x68739e1b4fa069e5, 0x4c191300a9207cf4, 0x9b613a1a38160c98,
154 0x2cc631eb015081c9, 0x52af80aad7b676f4, 0x904b38943300ca8f, 0x50a515c0d302620f,
155 0x52ae95b8a0c1f36c, 0x6a62ab87786774e2, 0x17ea45367ad58985, 0x92959c57166aa21b,
156 0x2a9d91bd1a9716b4, 0x552c2f8528220174, 0xd665856c96b47d17, 0x14c6cba13b6dca3b,
157 0x865f1c93ec9000d0, 0x23dda8b5e161910e, 0xc191ac4342717953, 0x6783fdb95e098f1d,
158 0x1a4c26a5cad1e8ee, 0xde96e2a1e33e3046, 0xa57e65bedcf9047e, 0xa1cdef163fe7f80c,
159 0xeb0abcc13feeb7b2, 0xaa158c61b0e44470, 0x98dc901679caf85b, 0x954046758f8d2e96,
160 0x56db5e99c5d8c68, 0x7bb8d36962a4ac81, 0x2e301b4ecb03821, 0x121c1b2df70f0e1c,
161 0x3fbdad1e8faa0543, 0x6efb222398a2f88b, 0x65760de4d96338e0, 0x15b2c58a67fb43fa,
162 0x22f1532c89367d77, 0x1f726ffdad411d9e, 0x42572b54dcedf3ba, 0x3f8e0f6e9f0bbb7b,
163 0x4b0e705c86571a1c, 0xf8c9b04f8bd75117, 0x67ed2e9e4545557, 0x57e8853f681bbf8c,
164 0x6f99d1fd5fdbf582, 0xd2aa9bd48ad692e2, 0x2efc88bddecfe616, 0x8e9779a1e119abf4,
165 0x52dfee4722a20b75, 0x79465be3aea146d6, 0x588997dbcbd5f005, 0x79bda8bcc5d4c650,
166 0x2384e131ed3b5330, 0x229cb1d89738aa26, 0x1526d1a020a96507, 0xc7b6ac961a740cb9,
167 0xe78cec14478c4f71, 0xaba61cfd8f1e2a71, 0x24123c8a37ae66f3, 0xbad8b07709aa215d,
168 0x7896fa53fd2418e7, 0x72265842e8c4f955, 0x9f6331fd80527661, 0x7c649eeddb382c9d,
169 0xd3b0708dd6b5ae84, 0xeda51f244551e15, 0xb7822c860b93dd44, 0xdf9afcc3c9cac88f,
170 0x9244b9816573be70, 0xf3d103887cc4ce2d, 0xb3295c2e5bcb0218, 0x85243b7a2e0af441,
171 0xbffd3df508d06098, 0x4908b967f6765c12, 0x8886ac94c0dabb, 0x9c7865af133eb6c0,
172 0x5946fee66e64d7b2, 0x7737bc5af713087f, 0xbec815a80782dd5d, 0xe7672cfe0f7945fb,
173 0xe1f80b6df5beece1, 0x5b749d3a22450fd6, 0xaf34a567bf838668, 0xa72a177d20943ceb,
174 0x257c45c1601c4922, 0x3d7c68f6fe36ce59, 0x1b8ef47186e06c96, 0x8040426656154c17,
175 0xc15f74f980647bda, 0x36389393336a78be, 0x15d174ed5536afe2, 0x51e702e8adb61f63,
176 0xc9c95ca3f1c08f30, 0x6653094c8531c93a, 0xf7be5dfc2eb3b5b, 0xb5e21ec5c63850b0,
177 0x9ab5f082e01021a5, 0x75c4ca38d7678fb1, 0xb20bd13e05e5bd67, 0x3378133e631fbaee,
178 0x17cb3686511aeb6e, 0x4c0dea4c80ec7bc, 0x21fe874bf5509300, 0xece4f84e34d52e54,
179 0x3f2649803ca9918b, 0xdb493adeac5c60f5, 0x7c02a1d153afedd, 0x2d08ceda0fef7967,
180 0x6a32e018e432b0ea, 0x86479f3ea38ad57e, 0x84e3e04f1e5877be, 0x41b898cb02772049,
181 0xd6dded3714d71084, 0x9df5b2f3a0ab275d, 0xd5ab652dfa73ee0a, 0x4633e03fa37d6edb,
182 0x226314b8c4b937ff, 0x45d66a00ab031188, 0xb93ce1cfbcd1eaa0, 0xf88e0756f7e7c1c1,
183 0xf3611966fed51e03, 0x81235048c662d9f7, 0xcc8275f866147b4f, 0xd3b3ca0f5033a863,
184 0x970212eb8c2b3429, 0xec848dd58f3449d6, 0xa1d527af824d09f2, 0x60bd5e91448b9cf4,
185 0x1210ddfac603aa88, 0xcbf4270f3407e25a, 0x212955fec55466a0, 0x3afeaef4c9ccc793,
186 0xdd114286ec304817, 0x849e6ae3c2cf794f, 0x71c08228d6a05310, 0x177e77779d155b11,
187 0xdc59148f219a9c04, 0xb0702a7802d5276d, 0x56085d6761aee015, 0x3f79ce06bcfb4f3,
188 0x459a1f917f8f3e0, 0xe4ea5635e8bcd512, 0xa88e99b63f135a39, 0x95bd628d77d39446,
189 0xe6432158ef4c7d98, 0xb349cd3d1c74369e, 0x25b1a32db58efb0a, 0xc2add3a44cecc0b5,
190 0x5d676629f23010b5, 0x9890b3a62599408e, 0xef68ea8144d97805, 0x429e0fda34046a85,
191 0x7723d9043053bf52, 0xbb78842d9b67ae91, 0x9155ef932192e6a3, 0xdb523ea403d39f6b,
192 0xdb8fa1eee23ea58, 0x7c735492524a3448, 0xc580cb82e81505, 0xb0be6a006414841c,
193 0xdec2e763b5cedaa5, 0x8da58bb23638af5f, 0xb0e6b33f6736e7d0, 0x8146bbcd3dd4df61,
194 0x978080148a8989bb, 0x7f8119caa3308095, 0x4e88c318ea0604f3, 0x6ee5262f16b3cf83,
195 0xc44395c7a578ace9, 0x92016ee635de27e1, 0xb8dc5ceb36e67fd2, 0x95c851d65bd35f8c,
196 0xbe393620503c49fa, 0x42af183b92eac923, 0xfef0e660435135ce, 0x262d67d480451ed1,
197 0x590f92e1ee0502b3, 0x18825c97d49e3700, 0x2cd8c30a848c9acf, 0x1025c7747fda0115,
198 0x54109f23e82590aa, 0x93917bf1f8325981, 0xda674b183fa0e3cf, 0x2a0b2467eb8aefc5,
199 0xb0085eb83468793c, 0x607cabb2c9d3a81b, 0xe7a6b6013804d665, 0x67629a769c1efede,
200 0x2830ab6ef6d10166, 0xffd02b0655332bd4, 0x19bd056c3117568f, 0x385a834785662c6f,
201 0x938b5d56bd5f7248, 0x969afe82dd4829c8, 0xf455d4ace41c797d, 0x23d9cd67eff27512,
202 0x2b0c7037ecb322e2, 0x73df193328258bda, 0x5d7ee05cf2054f93, 0xdabfbd5b46b61cea,
203 0xcea02d82546b96de, 0x2245d5e74d5f60ae, 0x842ca45f8ef2a44, 0x7505cc4e1c3060d8,
204 0x869146ac8e68565e, 0x22ea711fb30e73e3, 0x53cd64736898a0c0, 0xfa88458b920684df,
205 0xc3ae23f451e0616f, 0xe2dd69393141ff32, 0x98863ab129bcd866, 0x8c9756a40dd5b834,
206 0x2eeeef78c36fede5, 0xe84d2eb23e22153b, 0xb0ccc2f7ac541d78, 0x151faba0f513acfa,
207 0x4300e3cea0260717, 0xaba308c6d857d2d0, 0x5eb25dd325256c6a, 0x3342627b68038da4,
208 0x70d7d75526da35, 0x80ff3f5ea2ac3cf1, 0xe7434f2f026394b0, 0xa7c5ff17f7d2cb07,
209 0xdfed0bb33a06ff78, 0x485cc64d38ce2596, 0x88db8580147aa8fc, 0xf52a5111d693b973,
210 0xeeaa031c02b370a8, 0xbb3b1678222d0e81, 0x27b569f2a6630939, 0x2b301fa3e50efeb8,
211 0x4dbc1f85bf3f8972, 0xb37e4f2cb75a825b, 0x3c8848e0f1777cc7, 0x8fae2e6938ba00aa,
212 0xfb4674b50884992c, 0x2b765005b85b7388, 0xaaf0007fb9662ce5, 0x684bd59009a4ad65,
213 0x221ffead3d73ab35, 0xccfe6d02d46856b5, 0x54d3323359e1b114, 0xcb412202ed42f097,
214 0x15d63df422771b9b, 0x71852bca1581d14f, 0xf30dcbb6cf891e63, 0x478fb1eed3cc5a10,
215 0x849a3b52bc5bb196, 0x4c1a98dbc546dd81, 0x846dc8c2258ec4f8, 0xbd4da447c7340bd0,
216 0x8f1ee1d6a85b9db0, 0x123ebfa8aaec07f2, 0xae34948e375d4477, 0xd466a4177842d8e4,
217 0xd5108efeb19cac6, 0x3266f7db8f133bdb, 0xe69af4e5d8d767e4, 0xea0efc0331df64a2,
218 0xb879052746ed72ed, 0x2c8233cc84de4144, 0xdcd5dda825186731, 0xb9e3b679d268f34c,
219 0x7ce12e2fa95bda8b, 0xa34afd12e611a4c1, 0x6043d06ee7619f90, 0xca3a3d4813c0addf,
220 0x6e97a61d1e4b3c4f, 0x8cdeae467a4bb292, 0xf08a6c69e70076b5, 0x97aa5c3180d3edbe,
221 0xc39813e1573904d5, 0x42577549d026e8c8, 0xaf5827ffe259b62a, 0x9e1d48596c4f0b24,
222 0xab9dd230ba8efb64, 0x81769493b85868d4, 0x715b45c5e3952245, 0x84735e138d228f35,
223 0xf4f987da7d19c74d, 0x1bdc77979baf29b, 0x785b3640158e0278, 0x77fc9d00681bcdd,
224 0xb5980cc490dcab93, 0x9062c158196b8244, 0xc16af5418cc97c4a, 0xdd4a4e9e8e00e524,
225 0x870b554b629277f1, 0xf90ff72bb54322c0, 0xd4c273bc2199823, 0xeebc75970d438466,
226 0xe4cad67413074a53, 0x6eccde71bd09dc0c, 0x14278b0ca6b910b4, 0x6e8895f17cdb933c,
227 0xa0b3987821416e11, 0x71b7d24b81fa769f, 0x1d3b1a805b885a58, 0x1bc737b1719736a,
228 0xea4d1dbb8823037, 0xe50ce48c8469adbd, 0x34c2d5e6c41a888e, 0x446a756eb06dc3a4,
229 0xbac5ed8a8f90262, 0x7f1b76e0c707ab9d, 0xb31323309b94a12e, 0xf58269b9852f986e,
230 0x3b74c2b338c244fc, 0x879b46f23a4deae4, 0x3f2591e34cdce1c9, 0x73c6f81eb560ed5c,
231 0xd2aa923c7a5c18a9, 0x7170c1f7621cace9, 0xa18b327b11b951a, 0x2b36315510f56370,
232 0x5cfed2f703dfc0bb, 0x1e43b99175054c07, 0x392dfa3210e8013b, 0x65e0c5c0454ee693,
233 0x2a795f6f493349db, 0x17995ebdfe848db0, 0xf23174b823a52cf7, 0xaac6ef104bfd396e,
234 0xfa0f5b29156eeccd, 0x9ccb3590a6e88c1a, 0x2edae0b1b80aafab, 0x1e1e92baae39aa30,
235 0x24475af89cec7f33, 0xacdbeceaadb9936c, 0x7725948da8586e93, 0xcc05595e17947215,
236 0x1f3cbde17a508faa, 0x2795f58ff5c8919b, 0x309658d1748f30d3, 0xe90c11962e5ed4bb,
237 0xc22b876286d32e27, 0x495c8b667c6ea3dd, 0x84263045f7d6eab5, 0xf8d3a9ab1494a315,
238 0xabc42cf769a21d9d, 0x3fef7fb40bdf3a81, 0xfd35336e188925a3, 0xd472bdaf277ab26d,
239 0x4949e8ff51da2307, 0xbec86dce960ff3b, 0x1aa1ce4f70256b10, 0xd52986ff8cd700ea,
240 0x364d8efc0f5afad6, 0xca3d1958f57a9050, 0x17a0a2ec122dc677, 0x7992695be3363fd6,
241 0x5c66a265e0607da8, 0x7250114e050bb917, 0x30cd3a70bc7b723d, 0x7b77433392b3fbf8,
242 0x295bb7bf46318b38, 0xdb15025af2a71c65, 0x26a82b21ef67f50c, 0x14a5573d4fc798c1,
243 0xd8cad4642ec68e5e, 0x9276d7f60142822c, 0xf7b8efc27522e52f, 0xd0a3f36f6d340bed,
244 0x341260fb11765c02, 0xcd1d394d796702cc, 0x7d483ef031eb3346, 0x74eaab49374576c1,
245 0xa073bea32a71a273, 0xd65ce2552993b5cf, 0x8670afe77caaeb16, 0xb607f1455d072a47,
246 0x30ed96be92809559, 0xa58380a503c23c9c, 0x916aa68fb957a30d, 0x30c5a675bf19738c,
247 0xd4cbad34e4e4b886, 0xd6cb83061f2b0ebf, 0xceddb4040f535fa9, 0x778c586927b1e247,
248 0xe4bb5c4b6e0f3c3d, 0x3e857d671db80667, 0x2b909dd8725f1fa2, 0x558ffd0772db7841,
249 0x710f9638d3edb2c4, 0x21a4ccee53d46556, 0xf76e8e4737b9628b, 0x71cd157f23581c71,
250 0x68d8fded9b66efd6, 0x7d9f5e182c0b9457, 0x2140757748a217ff, 0xdd1e5365520b77a4,
251 0x644d8e4b2f30dcfa, 0xa1de42f4e9791564, 0x70e148ababfe9f86, 0xb97f463e0ac7daec,
252 0x82844f729d9fa554, 0x5c8475e84470c924, 0x3a83de748eac32fd, 0x68725fbc9c202c5b,
253};
254
255pub const mt32_seed = 0x7dc0d160;
256pub const mt32_data = []u32 {
257 0x59327332, 0x200858fa, 0xab53c028, 0x5c442427,
258 0xd8be0287, 0x3b69d304, 0x15fdf62f, 0x59b8ecd,
259 0x6d7ab30c, 0x3a3dd6f1, 0xc1b9773e, 0xa12fb017,
260 0xa805b5c1, 0x4a313ba5, 0xd82c790c, 0x8de311f2,
261 0xe7cb23dd, 0x784b2efb, 0x9743487c, 0x73e2f2fb,
262 0x1a7ac286, 0xaef90d, 0x6c0a4514, 0xae1d83aa,
263 0x412fcca1, 0x3acd2d28, 0xde78292f, 0x13237756,
264 0xdd6cdeba, 0x44ae4df9, 0x3e9902eb, 0x39e1cf20,
265 0x62f561b9, 0x6cbdf531, 0x4a000673, 0xb1c82daa,
266 0x896156ca, 0x75e410f2, 0x9c69e72c, 0x396b42bb,
267 0x25c97ec0, 0xe12173f1, 0x8dcd42e5, 0x82aac3e3,
268 0xcdc1c84d, 0x13509c0c, 0x46a696d2, 0xb89ad987,
269 0x92da5e7f, 0xaa87d8a9, 0xe433ff57, 0x80a7ee49,
270 0xd387cfcc, 0x7dc47d92, 0x21516140, 0x989ca465,
271 0xf2a8e002, 0x73b99ddb, 0x2204108f, 0x27e84890,
272 0x371c81c0, 0x9f581854, 0xc0841c35, 0x770f6804,
273 0x87c55f4e, 0xd29516bb, 0x2b6d6bde, 0x5541f6ee,
274 0x1ec9b182, 0x7d599729, 0x4f4b9a14, 0x6f8c8562,
275 0x2d5151aa, 0xb54f5bc, 0xa252452b, 0x2a4266da,
276 0x25a6b75d, 0x2d11106e, 0xc5d77943, 0xb10b6e0b,
277 0xeb5cae4a, 0x43a0dd53, 0xa40bea1f, 0x63e632c2,
278 0xf420b6ce, 0x8b080233, 0x7f70ae87, 0xf460f0d6,
279 0x147c7e74, 0x710692ea, 0xa0a7d8fb, 0xe7f05808,
280 0xa6173aaf, 0xae608de0, 0x8702036, 0xbf1bfc7b,
281 0xf14cd548, 0xbbc7553d, 0x5358dd1d, 0xcc0c1fe5,
282 0xfab6f78d, 0x9365c118, 0xf64216a3, 0xb4bdcf1b,
283 0xc90b8a7a, 0x8b7b78a, 0x4c7b6854, 0xba7b5628,
284 0xdd728c15, 0xcb1f8905, 0xa63e2342, 0xa78822,
285 0xbda61b18, 0x160a59fa, 0xeccf473b, 0xc5a445b5,
286 0x7aa86430, 0x362e0d7c, 0x8006a0cb, 0x8b11586f,
287 0x6677bba9, 0x6208cf27, 0xeec9b5, 0x3dfedfc9,
288 0x886cc0e8, 0x32ed77ca, 0x43525faf, 0x9786354a,
289 0x1a2eb378, 0xf0e6b168, 0x49064b09, 0x8ab39681,
290 0x7b6655fc, 0x35adb168, 0xc417d430, 0x2784288a,
291 0xea17836, 0xc85006e7, 0x673dfdc3, 0x42765688,
292 0xc2b9251, 0x840a45b, 0xcac98e2f, 0x1a6f9777,
293 0x34959b23, 0xf0dcec81, 0xcaa2c6c8, 0x1cf93061,
294 0x787e598d, 0xd5d9e31e, 0x14e08791, 0xd9d9d782,
295 0xef162f23, 0x238f4113, 0x23f42107, 0x6ed5cc3f,
296 0xa55e5a7c, 0x4650595, 0x5217da8b, 0x6eeaacdc,
297 0xb453d7b1, 0xfa1ff004, 0xb9d17f74, 0x2bd6a53e,
298 0xe4c2d9dd, 0xed66375e, 0xf8215568, 0x9bcadbb3,
299 0x9c4f9d51, 0xff68312, 0x82308422, 0x83e990b0,
300 0x38b6135b, 0x70e2aa13, 0xa30065d2, 0x6396a00,
301 0x77d423bc, 0xa93abf0a, 0xc7bb8c31, 0x5d7bd3d3,
302 0x6a374f2e, 0xe4b5bc88, 0x39f6e512, 0xd6aea995,
303 0x878c1bfa, 0x4636014d, 0x9caa2c09, 0x7ac4758b,
304 0xbd3b957e, 0x518c2fd6, 0xea009a2e, 0x542bf419,
305 0x59090006, 0xb1d94703, 0xe0d9eefc, 0xe7fccb17,
306 0x40111951, 0xf2560485, 0xb50ce9e1, 0xd7a1ee51,
307 0x28dffa99, 0x41d12275, 0xdd89a365, 0xf22eda29,
308 0x104f94ee, 0xe669983b, 0x6346a250, 0x86326fc5,
309 0xb7f347df, 0x3849a39f, 0xf433929a, 0xeea5155,
310 0x4cf9b778, 0x6bd7926a, 0xcda9496, 0xf430d7a2,
311 0x41637670, 0xaf3bbad6, 0xeb66e44e, 0x2499605d,
312 0x9988920d, 0xf9d652ef, 0x67aa80c0, 0x505073c9,
313 0x85cd418f, 0x9f83fb65, 0xf50b3eac, 0x812ba6bd,
314 0x74d61788, 0x86d64f3b, 0xb1f8fc1c, 0x3e2af667,
315 0x4d118a2, 0xd028ffa9, 0x32e88a44, 0x4ed9ba35,
316 0xea3c7030, 0xffe44aaf, 0x5e39c467, 0xeabcfebb,
317 0x53e656ec, 0xced701d0, 0x31020b02, 0x4b4c1dc5,
318 0x8744885c, 0xa8e93656, 0x3ef457e5, 0x272bde23,
319 0xe541477c, 0x3ad3ac04, 0x63eaa692, 0x81055cf9,
320 0x3ff5f782, 0xa8efe6bc, 0x15f37656, 0xaaaebf1d,
321 0xf73d461a, 0xe8b2c0b5, 0x5035ff48, 0x3a95e34b,
322 0x6f21d94f, 0x6f6d1f96, 0xdaf79f37, 0x826f69f3,
323 0x209a00b8, 0x2ad1b2f2, 0x2c64fb45, 0xcf8bf26e,
324 0x9befcff2, 0xc08f6951, 0x96d98205, 0xa267dcb5,
325 0xbc43ec5, 0xee6a7e1c, 0x49224eae, 0x14e820e,
326 0xbb340212, 0x68ed572c, 0x45e9e623, 0x1297f3af,
327 0x49a98ed2, 0xddd34ae8, 0x211838ab, 0x47e7652d,
328 0xb40430c6, 0xc8d3bd7, 0x4352356e, 0xf0e5cac9,
329 0x21880df4, 0xc16b343a, 0xd9ed7350, 0x17fe1f65,
330 0x6637192e, 0xd81c93aa, 0x7d6e17d2, 0xd407b13f,
331 0x425da072, 0x380d423d, 0x6ce57b22, 0x7b17ed17,
332 0x95fbf626, 0x768303d6, 0x76ab6b3e, 0x591491e3,
333 0x259f79ab, 0xd4babeaf, 0x9c7de2f8, 0x4fe6cb58,
334 0xf43680a9, 0x651a1266, 0x730ea3c8, 0x9188d4c5,
335 0x12d01e34, 0x47afb2e9, 0xb4b76d35, 0x5e5164bc,
336 0xc864fc46, 0x5d018aa7, 0x17fac975, 0x5a775fbd,
337 0x40e6fa14, 0x7a00b683, 0x99e4e102, 0x2f933b90,
338 0x474e14ba, 0xde1b0754, 0xe84aba2b, 0xb386cd43,
339 0x17ca77c9, 0x7b4f38ef, 0x803ea1a8, 0x93553947,
340 0x806c8224, 0x2608451e, 0x63157fe3, 0xaf53930e,
341 0x5dfe8c16, 0x65592bda, 0x7086eb3f, 0x838e6a50,
342 0xa27836d9, 0xf2f16d92, 0xdc0a981, 0xfbf8f915,
343 0x2caea00d, 0x86bb3e18, 0x6d94c209, 0x3bbbeb6c,
344 0x114d68f4, 0xc271e48f, 0xa3350dc1, 0xb8d55eb4,
345 0x68be5ee1, 0xbf22ef29, 0xd6e0aa54, 0x48f7219,
346 0x21aca253, 0xfbf07910, 0xfcdd61a8, 0x118a09b,
347 0x3f2bbde6, 0x46eea63f, 0xdb51ed16, 0xf8a9fc36,
348 0x31614dc0, 0xdd84f54d, 0xd2b66065, 0xdae0af99,
349 0x6d071a51, 0xbdbac46c, 0x15deee25, 0xf792e64c,
350 0x910194e8, 0xfc989a8f, 0x919727fd, 0x6f93a56c,
351 0x2df36e9a, 0xd395b948, 0xb026b54a, 0xf0938a5,
352 0xe9c64399, 0xb5cda15b, 0xb7b8dd41, 0x7146f944,
353 0x8d41ce2f, 0x47c74099, 0x2e5a8e5f, 0x28f7a19c,
354 0xef7a8ef9, 0x6a763eb9, 0xf13a3ec4, 0x9f352360,
355 0x42317561, 0x6c6a0ca5, 0x5e40b472, 0x3ddaadd4,
356 0x2f5d14eb, 0x5dd49aeb, 0xc89edb24, 0xa2da269b,
357 0x5cf0a38b, 0x8e2f435c, 0x40970e54, 0xa2cb730e,
358 0xf9d8c301, 0x8ef29fb1, 0xf08b1840, 0x7d45e4a2,
359 0xa0fe4ce1, 0x939a21c4, 0xfdeebfea, 0x4c661550,
360 0xdd304d1c, 0x3cdb078d, 0x94ae8db2, 0x4f6b4287,
361 0xffe64fa8, 0x50384bb0, 0x16cf5ed3, 0xa91a8fec,
362 0xdb8ebb1, 0x59c2898b, 0xd587edc9, 0xdec2e75a,
363 0x496ccdd2, 0x897db91d, 0xf8ea5149, 0x6bed4bad,
364 0xce76e472, 0x43c7f976, 0xb055dc01, 0x7ffd5671,
365 0xe193b86a, 0xe288ce11, 0x514d531e, 0xa42fa47e,
366 0xe7c0e194, 0xffc059ba, 0x26548e36, 0xe1f10d92,
367 0x3ef5d95e, 0xa6e69282, 0xffacb09e, 0xf4a16ff5,
368 0x9b7f03bd, 0x588c54b4, 0xc2b6eaa1, 0x2d83acdc,
369 0x7fdbb606, 0x2b160650, 0x9923e57e, 0x32bd23bd,
370 0x50cd6d4c, 0x205d901f, 0x810a9935, 0x27ce6e7a,
371 0xe0c6c66, 0xac06c99c, 0x4326aa9b, 0xe1af1e90,
372 0xe358c8b1, 0x2f601c2a, 0xefca77e7, 0x1a7ed2f8,
373 0x8ad2e191, 0xe5520809, 0x27084438, 0xe4d8e782,
374 0x5e8a4038, 0x87bba694, 0x65f07eba, 0x616f8f07,
375 0xc5565d9, 0x555955e4, 0xf41c2caa, 0xb085fbf5,
376 0xa5f9d9ff, 0x418fa0df, 0xec5a576d, 0x7fc332ab,
377 0x7683ed33, 0x968ef54b, 0x834d598d, 0x6833f356,
378 0x59dc7e7f, 0x779661dc, 0x58942dd4, 0x80387aab,
379 0xf6dac9e5, 0xe043be04, 0x2ae4f872, 0x881f8d01,
380 0x82cfd69d, 0x931f4648, 0x2a76ab31, 0xa3f1dd7c,
381 0xd7f4826a, 0xe74918da, 0xe4c98636, 0x441164f,
382 0x15a0e9aa, 0xce7480ad, 0xba39076b, 0x233aa8d,
383 0x6c32f0e6, 0x169c62bf, 0xa2cd17f6, 0xb5590084,
384 0xb2036f00, 0x18315935, 0x11e9c9c7, 0x25c77861,
385 0x41596cda, 0x635e5e02, 0x8f396cc, 0x4cd00d8d,
386 0xd665597e, 0x90f891ef, 0x547b93ee, 0x376959c1,
387 0xdc5fa80, 0x9b4797a6, 0x53673041, 0x25ab117a,
388 0x7b8b8292, 0xf4e99584, 0x5139da98, 0x30e2afeb,
389 0xff2664b9, 0x591eb6f0, 0x9e87e602, 0xf5e26193,
390 0x61831f07, 0xabc139f9, 0x984eda0a, 0xaea1b8da,
391 0x65c7410d, 0x2b84800d, 0x1d3cfec3, 0xd05cb8a1,
392 0x4529641b, 0x7d6712e6, 0xc38cbde7, 0xacad7787,
393 0xd8482f3a, 0xa5662eaa, 0x24836ee9, 0xf3b5cc97,
394 0x50a581ae, 0xff6004b6, 0x650fc547, 0x161898b1,
395 0xa7593447, 0x325827dd, 0xf1844a1a, 0x7eb56de2,
396 0x89882452, 0xfebb49a, 0xfe86ae9c, 0x7dba98b1,
397 0x1d65adb5, 0xb71acffa, 0x861215af, 0xc0f1496,
398 0x70967c72, 0x3803d127, 0x6c8fdd84, 0xe40991f1,
399 0x1343e3a, 0xf57b4e73, 0x25f34f76, 0xaebcdee8,
400 0x8752d71f, 0xfc710e54, 0x34f3af44, 0xfa7dea4e,
401 0x477d4d83, 0x42640ff1, 0x2c5c31ce, 0xa82de5e4,
402 0xcc813271, 0x4d40bf86, 0x4e416095, 0xb5ac332c,
403 0xd2d44703, 0xe4c5ef57, 0xde193a29, 0xbf3e7974,
404 0xbb313d75, 0x8dc973d5, 0x301b2657, 0x44dc5064,
405 0x8c58c633, 0x83424c74, 0xb7cbf7ac, 0xa04238c2,
406 0x6ceabd59, 0xd25e6fd0, 0x3409167, 0x42d6ef80,
407 0x1f47c437, 0xdb21e45f, 0x2fd48e29, 0x9498cfb7,
408 0xc9e4cb12, 0xc6dcf0df, 0xa1633c39, 0x1b349670,
409 0xf76d4a64, 0x15ecd8dd, 0x777bb76d, 0xc46008e7,
410 0x23d94e44, 0x78aa07de, 0x2eeac782, 0x3757b114,
411 0x2b22de2a, 0x37726519, 0xf107546d, 0xe9847f74,
412 0x449a4ea6, 0x2e31fa5a, 0xd719ea88, 0xb2115c87,
413 0xfa6b7231, 0xf72fc9ff, 0xcd22bc37, 0x9080778a,
414 0x93430a21, 0x97c24360, 0x6e5b1a76, 0x5e8baa7c,
415 0x300c94f8, 0x2843d9da, 0xdceac0ae, 0xeeed885,
416 0x1898ffd0, 0xa3bbee3c, 0xc16f8fd7, 0x82992b68,
417 0x39c153b6, 0x1b3ba4c8, 0x41e7c3ac, 0xcdf8f06a,
418 0xd40b8ae6, 0x4982b6c2, 0xb32f7437, 0x22ed3691,
419 0x16579a2a, 0xff9de457, 0xc421e8e4, 0x17c8f6cb,
420 0xa5c4a8da, 0x49bd8afa, 0xe2be081c, 0x95170f28,
421 0xd679fbdf, 0xcf39d563, 0x4e2d2ee9, 0x39471096,
422 0x3918bef0, 0x279b7679, 0xa5281a0f, 0x49481d6f,
423 0x11f95ee1, 0xd9df649f, 0x2993eb27, 0x48ad815f,
424 0x99cf306d, 0xca9457e4, 0xc27c51d2, 0xc2a838ec,
425 0x537faf4c, 0x55dccddf, 0x8df5aeb8, 0xabb317ca,
426 0xfc1bcf6b, 0x669c2b1b, 0x719b62d5, 0x6b9325cf,
427 0xc123d0d3, 0x2ddc6ace, 0x27fdc30a, 0xd3f93cd8,
428 0x704f5486, 0xd3f448ec, 0xbbd1e32c, 0x3bcd4c0b,
429 0x86f8166, 0x957db888, 0x899b6a5e, 0x270dc8b7,
430 0xff16222e, 0x51e139a8, 0x3d8b4b9f, 0x68d20818,
431 0xa639ad00, 0x4c2e0fd2, 0xb4949cdc, 0x2ab6eb32,
432 0xdd0c67ad, 0xd2208cbe, 0xcd17a0bc, 0xacc541f7,
433 0xfa9e714f, 0x316d31a7, 0xed79fa91, 0xb5c0e980,
434 0x412ecc9b, 0x9815753, 0xd0df1f43, 0x8e37dbb9,
435 0xe640df75, 0x379c2fb6, 0xc7ed26a4, 0xc5190400,
436 0x1cc81b53, 0xcb0b0cd5, 0x360f061b, 0x6d90284e,
437 0x83c05bd0, 0xbd80bae9, 0xd584ef12, 0x228a46ec,
438 0x657c4fbe, 0x5ca1043c, 0x852aca0f, 0x31ce950,
439 0x33ee2cd8, 0x3cdecbf7, 0x787ef08c, 0xea610ee,
440 0x47c1db89, 0x90eeda11, 0x74f8d429, 0x51d3a4c5,
441 0x3135b401, 0x2e14783c, 0xb9af855c, 0xb66348d9,
442 0xa3a47387, 0x6eb72af1, 0x7bb56088, 0xc664542d,
443 0x7ed96b8, 0x995870a8, 0x385b1fd6, 0xa430680d,
444 0x98a883ec, 0x2497a389, 0x7a880627, 0x8350ba9d,
445 0x4cb35c33, 0x30bf6b14, 0x8695a469, 0x9a81e44b,
446 0x8bb27c9a, 0xbfb6a4dd, 0xbae7cf6e, 0x4ebccc87,
447 0xb712ed3d, 0x31e90365, 0xcc1fa63f, 0x32b93df6,
448 0xbad4c7bc, 0xb2570e17, 0x73fa21be, 0x5c02a8d2,
449 0x94446d75, 0x7265f3ad, 0xd58487a2, 0x919b7a07,
450 0xbe2d0e05, 0xd36ccf4f, 0x6d5c66d7, 0x8448522f,
451 0x8409c294, 0x6f1c7af7, 0x173a13bc, 0x1b3e4a0b,
452 0x705b941b, 0x77eb584f, 0x85b68458, 0x8e3ad1ac,
453 0x4aa99702, 0x7ae1b24c, 0x899ba29c, 0x860a3711,
454 0xabe53a4f, 0x37870133, 0x1ed7cb89, 0xea539762,
455 0x4ba64130, 0x48517a2d, 0xce0a869d, 0x937ba48,
456 0xd0f234c4, 0xf9b2cf26, 0xc3c311f0, 0x153d09a9,
457 0x404d3af9, 0x9f7edbc1, 0xbdcecded, 0x97969ba8,
458 0x3379437, 0xadd3c893, 0x7c024639, 0x459390b,
459 0xcb7c7320, 0xa5c63725, 0x65907e3e, 0xbf70583b,
460 0xcebb601b, 0x4edfb286, 0x9350336f, 0xdfb4be76,
461 0x88b56f39, 0x9937d7f9, 0xa12a286d, 0x34f141c,
462 0xa2e75c15, 0xd69a7060, 0x931340c3, 0x22447f25,
463 0xe8aed82c, 0xd76a9ae7, 0xc967288, 0xe572facd,
464 0xbe82b0ee, 0x10f5dce1, 0x4f03ee35, 0x2340b923,
465 0xf4fb6bd0, 0x64adbf01, 0x3d277a0a, 0x39e76f2c,
466 0xe3c024d9, 0x57869c82, 0x743b7826, 0xf66f1574,
467 0xc93965c, 0xf86a552, 0x13557069, 0x9e0845de,
468 0xaee084f9, 0x5eafaedb, 0xc06f5f3, 0x9051f6ea,
469 0x98fceda2, 0x2af2f8cc, 0x6c41b5a8, 0xc1af74de,
470 0x57302276, 0x253923c9, 0xd79996b3, 0x8ecb3141,
471 0x641387cc, 0xf87a4101, 0x96a50c76, 0xbcf24a11,
472 0x87b6bb6, 0x58ee501b, 0xaa859695, 0xb2eed107,
473 0x554173f0, 0xb12ec0e6, 0x57785c1b, 0x53685c9a,
474 0x114c3163, 0x9383cf19, 0x31fd7cdf, 0xaeb8225c,
475 0x58774fe7, 0x54700ad4, 0xad418726, 0xf055b71c,
476 0x7d31237f, 0xdd97cad5, 0xcdd5325e, 0x42f2acf4,
477 0x4bed262b, 0x7a8faaf2, 0x2b1eafdd, 0xa1b806ac,
478 0x26965c6e, 0xb41b7168, 0x15e2e70b, 0x7daa8e13,
479 0x6198aa5a, 0xc9b8b94c, 0x339b5754, 0xcd3b285c,
480 0xffd1486c, 0xf224979a, 0xafb89ec5, 0x222058c,
481 0xcb4814d0, 0x2b0e7c7d, 0x9eb25b84, 0x271564b0,
482 0xbb72e076, 0x48251020, 0x18008023, 0x48d10005,
483 0x4a452eaa, 0xb2365308, 0x19cdb632, 0x1fd56d04,
484 0xffa5ff2a, 0xaba89e42, 0x388fc17d, 0xea61c00f,
485 0x5156273d, 0x776f1a56, 0x8d539d28, 0x289c01cb,
486 0x857aa71f, 0x348e411f, 0xc9eb3c91, 0x67a61079,
487 0xe4276a0f, 0x45bdc15f, 0x8e0a698e, 0xbdefc310,
488 0x82377ba6, 0x3bfbf404, 0xcbf22c79, 0x35f501bc,
489 0xb16044a7, 0xeffdb8, 0xdbac383d, 0x7816663f,
490 0x18f5a318, 0x3d04f1cb, 0x735da9b4, 0x75e339a1,
491 0x5b6c55f, 0x1c18887e, 0xf698e14f, 0x338a6da1,
492 0xdac85699, 0x1aca7768, 0x8eb0fa7a, 0xc98fa71d,
493 0x3b794408, 0x92913041, 0xf8dc8827, 0x1cf706e9,
494 0x3aeee292, 0x321dbaa8, 0xee1eb8d1, 0x23554be9,
495 0x811c7804, 0xf0f4de6b, 0xd457e382, 0xeda56795,
496 0xeffdfc71, 0xf2a52829, 0xa7460732, 0x2c1321c0,
497 0x2f734db0, 0xf04ecb0b, 0xec7d777e, 0x43c54317,
498 0xccaa74cd, 0xfe49dd9d, 0x4c509829, 0x278f9bd7,
499 0x581dc500, 0x4ad38c2e, 0xcbee1047, 0x13302c1c,
500 0xbc0cb734, 0xc1c8f234, 0x1df52b35, 0xd8815548,
501 0x319edefb, 0x437cebe5, 0x3dcb6026, 0xe9d4f93f,
502 0xb2661154, 0xeb8c15a0, 0xb008505, 0x5f869981,
503 0xf5588ca4, 0xd6929c5b, 0xa3dd13d1, 0xdc863314,
504 0x891a454f, 0x91737e49, 0x5064d4d8, 0x2fd32675,
505 0xadefe9b1, 0xdde32b11, 0x741bbd6, 0x3b4363a9,
506 0xb121d9e8, 0x916ca61d, 0x38c0af15, 0x5e3dfd72,
507};
std/sort.zig+77-77
......@@ -67,7 +67,7 @@ const Iterator = struct {
6767 self.numerator -= self.denominator;
6868 self.decimal += 1;
6969 }
70
70
7171 return Range {.start = start, .end = self.decimal};
7272 }
7373
......@@ -82,7 +82,7 @@ const Iterator = struct {
8282 self.numerator_step -= self.denominator;
8383 self.decimal_step += 1;
8484 }
85
85
8686 return (self.decimal_step < self.size);
8787 }
8888
......@@ -219,7 +219,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
219219 var B1 = iterator.nextRange();
220220 var A2 = iterator.nextRange();
221221 var B2 = iterator.nextRange();
222
222
223223 if (lessThan(items[B1.end - 1], items[A1.start])) {
224224 // the two ranges are in reverse order, so copy them in reverse order into the cache
225225 mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]);
......@@ -230,13 +230,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
230230 } else {
231231 // if A1, B1, A2, and B2 are all in order, skip doing anything else
232232 if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue;
233
233
234234 // copy A1 and B1 into the cache in the same order
235235 mem.copy(T, cache[0..], items[A1.start..A1.end]);
236236 mem.copy(T, cache[A1.length()..], items[B1.start..B1.end]);
237237 }
238238 A1 = Range.init(A1.start, B1.end);
239
239
240240 // merge A2 and B2 into the cache
241241 if (lessThan(items[B2.end - 1], items[A2.start])) {
242242 // the two ranges are in reverse order, so copy them in reverse order into the cache
......@@ -251,11 +251,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
251251 mem.copy(T, cache[A1.length() + A2.length()..], items[B2.start..B2.end]);
252252 }
253253 A2 = Range.init(A2.start, B2.end);
254
254
255255 // merge A1 and A2 from the cache into the items
256256 const A3 = Range.init(0, A1.length());
257257 const B3 = Range.init(A1.length(), A1.length() + A2.length());
258
258
259259 if (lessThan(cache[B3.end - 1], cache[A3.start])) {
260260 // the two ranges are in reverse order, so copy them in reverse order into the items
261261 mem.copy(T, items[A1.start + A2.length()..], cache[A3.start..A3.end]);
......@@ -269,17 +269,17 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
269269 mem.copy(T, items[A1.start + A1.length()..], cache[B3.start..B3.end]);
270270 }
271271 }
272
272
273273 // we merged two levels at the same time, so we're done with this level already
274274 // (iterator.nextLevel() is called again at the bottom of this outer merge loop)
275275 _ = iterator.nextLevel();
276
276
277277 } else {
278278 iterator.begin();
279279 while (!iterator.finished()) {
280280 var A = iterator.nextRange();
281281 var B = iterator.nextRange();
282
282
283283 if (lessThan(items[B.end - 1], items[A.start])) {
284284 // the two ranges are in reverse order, so a simple rotation should fix it
285285 mem.rotate(T, items[A.start..B.end], A.length());
......@@ -301,10 +301,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
301301 // 6. merge each A block with any B values that follow, using the cache or the second internal buffer
302302 // 7. sort the second internal buffer if it exists
303303 // 8. redistribute the two internal buffers back into the items
304
304
305305 var block_size: usize = math.sqrt(iterator.length());
306306 var buffer_size = iterator.length()/block_size + 1;
307
307
308308 // as an optimization, we really only need to pull out the internal buffers once for each level of merges
309309 // after that we can reuse the same buffers over and over, then redistribute it when we're finished with this level
310310 var A: Range = undefined;
......@@ -322,11 +322,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
322322
323323 var buffer1 = Range.init(0, 0);
324324 var buffer2 = Range.init(0, 0);
325
325
326326 // find two internal buffers of size 'buffer_size' each
327327 find = buffer_size + buffer_size;
328328 var find_separately = false;
329
329
330330 if (block_size <= cache.len) {
331331 // if every A block fits into the cache then we won't need the second internal buffer,
332332 // so we really only need to find 'buffer_size' unique values
......@@ -336,21 +336,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
336336 find = buffer_size;
337337 find_separately = true;
338338 }
339
339
340340 // we need to find either a single contiguous space containing 2√A unique values (which will be split up into two buffers of size √A each),
341341 // or we need to find one buffer of < 2√A unique values, and a second buffer of √A unique values,
342342 // OR if we couldn't find that many unique values, we need the largest possible buffer we can get
343
343
344344 // in the case where it couldn't find a single buffer of at least √A unique values,
345345 // all of the Merge steps must be replaced by a different merge algorithm (MergeInPlace)
346346 iterator.begin();
347347 while (!iterator.finished()) {
348348 A = iterator.nextRange();
349349 B = iterator.nextRange();
350
350
351351 // just store information about where the values will be pulled from and to,
352352 // as well as how many values there are, to create the two internal buffers
353
353
354354 // check A for the number of unique values we need to fill an internal buffer
355355 // these values will be pulled out to the start of A
356356 last = A.start;
......@@ -360,7 +360,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
360360 if (index == A.end) break;
361361 }
362362 index = last;
363
363
364364 if (count >= buffer_size) {
365365 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffer
366366 pull[pull_index] = Pull {
......@@ -370,7 +370,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
370370 .to = A.start,
371371 };
372372 pull_index = 1;
373
373
374374 if (count == buffer_size + buffer_size) {
375375 // we were able to find a single contiguous section containing 2√A unique values,
376376 // so this section can be used to contain both of the internal buffers we'll need
......@@ -405,7 +405,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
405405 .to = A.start,
406406 };
407407 }
408
408
409409 // check B for the number of unique values we need to fill an internal buffer
410410 // these values will be pulled out to the end of B
411411 last = B.end - 1;
......@@ -415,7 +415,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
415415 if (index == B.start) break;
416416 }
417417 index = last;
418
418
419419 if (count >= buffer_size) {
420420 // keep track of the range within the items where we'll need to "pull out" these values to create the internal buffe
421421 pull[pull_index] = Pull {
......@@ -425,7 +425,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
425425 .to = B.end,
426426 };
427427 pull_index = 1;
428
428
429429 if (count == buffer_size + buffer_size) {
430430 // we were able to find a single contiguous section containing 2√A unique values,
431431 // so this section can be used to contain both of the internal buffers we'll need
......@@ -449,7 +449,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
449449 // buffer2 will be pulled out from a 'B' subarray, so if the first buffer was pulled out from the corresponding 'A' subarray,
450450 // we need to adjust the end point for that A subarray so it knows to stop redistributing its values before reaching buffer2
451451 if (pull[0].range.start == A.start) pull[0].range.end -= pull[1].count;
452
452
453453 // we found a second buffer in an 'B' subarray containing √A unique values, so we're done!
454454 buffer2 = Range.init(B.end - count, B.end);
455455 break;
......@@ -465,12 +465,12 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
465465 };
466466 }
467467 }
468
468
469469 // pull out the two ranges so we can use them as internal buffers
470470 pull_index = 0;
471471 while (pull_index < 2) : (pull_index += 1) {
472472 const length = pull[pull_index].count;
473
473
474474 if (pull[pull_index].to < pull[pull_index].from) {
475475 // we're pulling the values out to the left, which means the start of an A subarray
476476 index = pull[pull_index].from;
......@@ -493,27 +493,27 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
493493 }
494494 }
495495 }
496
496
497497 // adjust block_size and buffer_size based on the values we were able to pull out
498498 buffer_size = buffer1.length();
499499 block_size = iterator.length()/buffer_size + 1;
500
500
501501 // the first buffer NEEDS to be large enough to tag each of the evenly sized A blocks,
502502 // so this was originally here to test the math for adjusting block_size above
503503 // assert((iterator.length() + 1)/block_size <= buffer_size);
504
504
505505 // now that the two internal buffers have been created, it's time to merge each A+B combination at this level of the merge sort!
506506 iterator.begin();
507507 while (!iterator.finished()) {
508508 A = iterator.nextRange();
509509 B = iterator.nextRange();
510
510
511511 // remove any parts of A or B that are being used by the internal buffers
512512 start = A.start;
513513 if (start == pull[0].range.start) {
514514 if (pull[0].from > pull[0].to) {
515515 A.start += pull[0].count;
516
516
517517 // if the internal buffer takes up the entire A or B subarray, then there's nothing to merge
518518 // this only happens for very small subarrays, like √4 = 2, 2 * (2 internal buffers) = 4,
519519 // which also only happens when cache.len is small or 0 since it'd otherwise use MergeExternal
......@@ -532,25 +532,25 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
532532 if (B.length() == 0) continue;
533533 }
534534 }
535
535
536536 if (lessThan(items[B.end - 1], items[A.start])) {
537537 // the two ranges are in reverse order, so a simple rotation should fix it
538538 mem.rotate(T, items[A.start..B.end], A.length());
539539 } else if (lessThan(items[A.end], items[A.end - 1])) {
540540 // these two ranges weren't already in order, so we'll need to merge them!
541541 var findA: usize = undefined;
542
542
543543 // break the remainder of A into blocks. firstA is the uneven-sized first A block
544544 var blockA = Range.init(A.start, A.end);
545545 var firstA = Range.init(A.start, A.start + blockA.length() % block_size);
546
546
547547 // swap the first value of each A block with the value in buffer1
548548 var indexA = buffer1.start;
549549 index = firstA.end;
550550 while (index < blockA.end) : ({indexA += 1; index += block_size;}) {
551551 mem.swap(T, &items[indexA], &items[index]);
552552 }
553
553
554554 // start rolling the A blocks through the B blocks!
555555 // whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well
556556 var lastA = firstA;
......@@ -558,7 +558,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
558558 var blockB = Range.init(B.start, B.start + math.min(block_size, B.length()));
559559 blockA.start += firstA.length();
560560 indexA = buffer1.start;
561
561
562562 // if the first unevenly sized A block fits into the cache, copy it there for when we go to Merge it
563563 // otherwise, if the second buffer is available, block swap the contents into that
564564 if (lastA.length() <= cache.len) {
......@@ -566,7 +566,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
566566 } else if (buffer2.length() > 0) {
567567 blockSwap(T, items, lastA.start, buffer2.start, lastA.length());
568568 }
569
569
570570 if (blockA.length() > 0) {
571571 while (true) {
572572 // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block,
......@@ -575,7 +575,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
575575 // figure out where to split the previous B block, and rotate it at the split
576576 const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan);
577577 const B_remaining = lastB.end - B_split;
578
578
579579 // swap the minimum A block to the beginning of the rolling A blocks
580580 var minA = blockA.start;
581581 findA = minA + block_size;
......@@ -585,16 +585,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
585585 }
586586 }
587587 blockSwap(T, items, blockA.start, minA, block_size);
588
588
589589 // swap the first item of the previous A block back with its original value, which is stored in buffer1
590590 mem.swap(T, &items[blockA.start], &items[indexA]);
591591 indexA += 1;
592
592
593593 // locally merge the previous A block with the B values that follow it
594594 // if lastA fits into the external cache we'll use that (with MergeExternal),
595595 // or if the second internal buffer exists we'll use that (with MergeInternal),
596596 // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace)
597
597
598598 if (lastA.length() <= cache.len) {
599599 mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]);
600600 } else if (buffer2.length() > 0) {
......@@ -602,7 +602,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
602602 } else {
603603 mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan);
604604 }
605
605
606606 if (buffer2.length() > 0 or block_size <= cache.len) {
607607 // copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway
608608 if (block_size <= cache.len) {
......@@ -610,7 +610,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
610610 } else {
611611 blockSwap(T, items, blockA.start, buffer2.start, block_size);
612612 }
613
613
614614 // this is equivalent to rotating, but faster
615615 // the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it
616616 // either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs
......@@ -619,21 +619,21 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
619619 // we are unable to use the 'buffer2' trick to speed up the rotation operation since buffer2 doesn't exist, so perform a normal rotation
620620 mem.rotate(T, items[B_split..blockA.start + block_size], blockA.start - B_split);
621621 }
622
622
623623 // update the range for the remaining A blocks, and the range remaining from the B block after it was split
624624 lastA = Range.init(blockA.start - B_remaining, blockA.start - B_remaining + block_size);
625625 lastB = Range.init(lastA.end, lastA.end + B_remaining);
626
626
627627 // if there are no more A blocks remaining, this step is finished!
628628 blockA.start += block_size;
629629 if (blockA.length() == 0)
630630 break;
631
631
632632 } else if (blockB.length() < block_size) {
633633 // move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation
634634 // the cache is disabled here since it might contain the contents of the previous A block
635635 mem.rotate(T, items[blockA.start..blockB.end], blockB.start - blockA.start);
636
636
637637 lastB = Range.init(blockA.start, blockA.start + blockB.length());
638638 blockA.start += blockB.length();
639639 blockA.end += blockB.length();
......@@ -642,11 +642,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
642642 // roll the leftmost A block to the end by swapping it with the next B block
643643 blockSwap(T, items, blockA.start, blockB.start, block_size);
644644 lastB = Range.init(blockA.start, blockA.start + block_size);
645
645
646646 blockA.start += block_size;
647647 blockA.end += block_size;
648648 blockB.start += block_size;
649
649
650650 if (blockB.end > B.end - block_size) {
651651 blockB.end = B.end;
652652 } else {
......@@ -655,7 +655,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
655655 }
656656 }
657657 }
658
658
659659 // merge the last A block with the remaining B values
660660 if (lastA.length() <= cache.len) {
661661 mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]);
......@@ -666,14 +666,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
666666 }
667667 }
668668 }
669
669
670670 // when we're finished with this merge step we should have the one or two internal buffers left over, where the second buffer is all jumbled up
671671 // insertion sort the second buffer, then redistribute the buffers back into the items using the opposite process used for creating the buffer
672
672
673673 // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort,
674674 // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here
675675 insertionSort(T, items[buffer2.start..buffer2.end], lessThan);
676
676
677677 pull_index = 0;
678678 while (pull_index < 2) : (pull_index += 1) {
679679 var unique = pull[pull_index].count * 2;
......@@ -702,7 +702,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
702702 }
703703 }
704704 }
705
705
706706 // double the size of each A and B subarray that will be merged in the next level
707707 if (!iterator.nextLevel()) break;
708708 }
......@@ -711,37 +711,37 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn(lhs: &const T, rhs: &cons
711711// merge operation without a buffer
712712fn mergeInPlace(comptime T: type, items: []T, A_arg: &const Range, B_arg: &const Range, lessThan: fn(&const T,&const T)bool) void {
713713 if (A_arg.length() == 0 or B_arg.length() == 0) return;
714
714
715715 // this just repeatedly binary searches into B and rotates A into position.
716716 // the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
717717 // but I decided to stick with this because it had better situational performance
718 //
718 //
719719 // (Hwang and Lin is designed for merging subarrays of very different sizes,
720720 // but WikiSort almost always uses subarrays that are roughly the same size)
721 //
721 //
722722 // normally this is incredibly suboptimal, but this function is only called
723723 // when none of the A or B blocks in any subarray contained 2√A unique values,
724724 // which places a hard limit on the number of times this will ACTUALLY need
725725 // to binary search and rotate.
726 //
726 //
727727 // according to my analysis the worst case is √A rotations performed on √A items
728728 // once the constant factors are removed, which ends up being O(n)
729 //
729 //
730730 // again, this is NOT a general-purpose solution – it only works well in this case!
731731 // kind of like how the O(n^2) insertion sort is used in some places
732732
733733 var A = *A_arg;
734734 var B = *B_arg;
735
735
736736 while (true) {
737737 // find the first place in B where the first item in A needs to be inserted
738738 const mid = binaryFirst(T, items, items[A.start], B, lessThan);
739
739
740740 // rotate A into place
741741 const amount = mid - A.end;
742742 mem.rotate(T, items[A.start..mid], A.length());
743743 if (B.end == mid) break;
744
744
745745 // calculate the new A and B ranges
746746 B.start = mid;
747747 A = Range.init(A.start + amount, B.start);
......@@ -757,7 +757,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
757757 var A_count: usize = 0;
758758 var B_count: usize = 0;
759759 var insert: usize = 0;
760
760
761761 if (B.length() > 0 and A.length() > 0) {
762762 while (true) {
763763 if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) {
......@@ -773,7 +773,7 @@ fn mergeInternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
773773 }
774774 }
775775 }
776
776
777777 // swap the remainder of A into the final array
778778 blockSwap(T, items, buffer.start + A_count, A.start + insert, A.length() - A_count);
779779}
......@@ -790,56 +790,56 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s
790790fn findFirstForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
791791 if (range.length() == 0) return range.start;
792792 const skip = math.max(range.length()/unique, usize(1));
793
793
794794 var index = range.start + skip;
795795 while (lessThan(items[index - 1], value)) : (index += skip) {
796796 if (index >= range.end - skip) {
797797 return binaryFirst(T, items, value, Range.init(index, range.end), lessThan);
798798 }
799799 }
800
800
801801 return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan);
802802}
803803
804804fn findFirstBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
805805 if (range.length() == 0) return range.start;
806806 const skip = math.max(range.length()/unique, usize(1));
807
807
808808 var index = range.end - skip;
809809 while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) {
810810 if (index < range.start + skip) {
811811 return binaryFirst(T, items, value, Range.init(range.start, index), lessThan);
812812 }
813813 }
814
814
815815 return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan);
816816}
817817
818818fn findLastForward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
819819 if (range.length() == 0) return range.start;
820820 const skip = math.max(range.length()/unique, usize(1));
821
821
822822 var index = range.start + skip;
823823 while (!lessThan(value, items[index - 1])) : (index += skip) {
824824 if (index >= range.end - skip) {
825825 return binaryLast(T, items, value, Range.init(index, range.end), lessThan);
826826 }
827827 }
828
828
829829 return binaryLast(T, items, value, Range.init(index - skip, index), lessThan);
830830}
831831
832832fn findLastBackward(comptime T: type, items: []T, value: &const T, range: &const Range, lessThan: fn(&const T,&const T)bool, unique: usize) usize {
833833 if (range.length() == 0) return range.start;
834834 const skip = math.max(range.length()/unique, usize(1));
835
835
836836 var index = range.end - skip;
837837 while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) {
838838 if (index < range.start + skip) {
839839 return binaryLast(T, items, value, Range.init(range.start, index), lessThan);
840840 }
841841 }
842
842
843843 return binaryLast(T, items, value, Range.init(index, index + skip), lessThan);
844844}
845845
......@@ -885,7 +885,7 @@ fn mergeInto(comptime T: type, from: []T, A: &const Range, B: &const Range, less
885885 const A_last = A.end;
886886 const B_last = B.end;
887887 var insert_index: usize = 0;
888
888
889889 while (true) {
890890 if (!lessThan(from[B_index], from[A_index])) {
891891 into[insert_index] = from[A_index];
......@@ -916,7 +916,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
916916 var insert_index: usize = A.start;
917917 const A_last = A.length();
918918 const B_last = B.end;
919
919
920920 if (B.length() > 0 and A.length() > 0) {
921921 while (true) {
922922 if (!lessThan(items[B_index], cache[A_index])) {
......@@ -932,7 +932,7 @@ fn mergeExternal(comptime T: type, items: []T, A: &const Range, B: &const Range,
932932 }
933933 }
934934 }
935
935
936936 // copy the remainder of A into the final array
937937 mem.copy(T, items[insert_index..], cache[A_index..A_last]);
938938}
......@@ -1081,11 +1081,11 @@ test "another sort case" {
10811081}
10821082
10831083test "sort fuzz testing" {
1084 var rng = std.rand.Rand.init(0x12345678);
1084 var prng = std.rand.DefaultPrng.init(0x12345678);
10851085 const test_case_count = 10;
10861086 var i: usize = 0;
10871087 while (i < test_case_count) : (i += 1) {
1088 fuzzTest(&rng);
1088 fuzzTest(&prng.random);
10891089 }
10901090}
10911091