| author | |
| committer | |
| log | af35b73b9929b9d7a698101190b6f0d27ce27542 |
| tree | 0ec91063a9bcf72f48ab36487813c5013c2ed820 |
| parent | 5017a1d895847df6cc02dc4bedd02aa341177171 |
| parent | 69d9f322ee380a0a22a1d93959f69699ea50d77d |
| signature |
2 files changed, 111 insertions(+), 5 deletions(-)
std/math.zig+11-5| ... | @@ -288,10 +288,8 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T { | ... | @@ -288,10 +288,8 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T { |
| 288 | const abs_shift_amt = absCast(shift_amt); | 288 | const abs_shift_amt = absCast(shift_amt); |
| 289 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); | 289 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); |
| 290 | 290 | ||
| 291 | if (@typeOf(shift_amt).is_signed) { | 291 | if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) { |
| 292 | if (shift_amt >= 0) { | 292 | if (shift_amt < 0) { |
| 293 | return a << casted_shift_amt; | ||
| 294 | } else { | ||
| 295 | return a >> casted_shift_amt; | 293 | return a >> casted_shift_amt; |
| 296 | } | 294 | } |
| 297 | } | 295 | } |
| ... | @@ -304,6 +302,10 @@ test "math.shl" { | ... | @@ -304,6 +302,10 @@ test "math.shl" { |
| 304 | testing.expect(shl(u8, 0b11111111, usize(8)) == 0); | 302 | testing.expect(shl(u8, 0b11111111, usize(8)) == 0); |
| 305 | testing.expect(shl(u8, 0b11111111, usize(9)) == 0); | 303 | testing.expect(shl(u8, 0b11111111, usize(9)) == 0); |
| 306 | testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111); | 304 | testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111); |
| 305 | testing.expect(shl(u8, 0b11111111, 3) == 0b11111000); | ||
| 306 | testing.expect(shl(u8, 0b11111111, 8) == 0); | ||
| 307 | testing.expect(shl(u8, 0b11111111, 9) == 0); | ||
| 308 | testing.expect(shl(u8, 0b11111111, -2) == 0b00111111); | ||
| 307 | } | 309 | } |
| 308 | 310 | ||
| 309 | /// Shifts right. Overflowed bits are truncated. | 311 | /// Shifts right. Overflowed bits are truncated. |
| ... | @@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T { | ... | @@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T { |
| 312 | const abs_shift_amt = absCast(shift_amt); | 314 | const abs_shift_amt = absCast(shift_amt); |
| 313 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); | 315 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); |
| 314 | 316 | ||
| 315 | if (@typeOf(shift_amt).is_signed) { | 317 | if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) { |
| 316 | if (shift_amt >= 0) { | 318 | if (shift_amt >= 0) { |
| 317 | return a >> casted_shift_amt; | 319 | return a >> casted_shift_amt; |
| 318 | } else { | 320 | } else { |
| ... | @@ -328,6 +330,10 @@ test "math.shr" { | ... | @@ -328,6 +330,10 @@ test "math.shr" { |
| 328 | testing.expect(shr(u8, 0b11111111, usize(8)) == 0); | 330 | testing.expect(shr(u8, 0b11111111, usize(8)) == 0); |
| 329 | testing.expect(shr(u8, 0b11111111, usize(9)) == 0); | 331 | testing.expect(shr(u8, 0b11111111, usize(9)) == 0); |
| 330 | testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100); | 332 | testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100); |
| 333 | testing.expect(shr(u8, 0b11111111, 3) == 0b00011111); | ||
| 334 | testing.expect(shr(u8, 0b11111111, 8) == 0); | ||
| 335 | testing.expect(shr(u8, 0b11111111, 9) == 0); | ||
| 336 | testing.expect(shr(u8, 0b11111111, -2) == 0b11111100); | ||
| 331 | } | 337 | } |
| 332 | 338 | ||
| 333 | /// Rotates right. Only unsigned values can be rotated. | 339 | /// Rotates right. Only unsigned values can be rotated. |
std/rand.zig+100| ... | @@ -18,6 +18,7 @@ const std = @import("std.zig"); | ... | @@ -18,6 +18,7 @@ const std = @import("std.zig"); |
| 18 | const builtin = @import("builtin"); | 18 | const builtin = @import("builtin"); |
| 19 | const assert = std.debug.assert; | 19 | const assert = std.debug.assert; |
| 20 | const expect = std.testing.expect; | 20 | const expect = std.testing.expect; |
| 21 | const expectEqual = std.testing.expectEqual; | ||
| 21 | const mem = std.mem; | 22 | const mem = std.mem; |
| 22 | const math = std.math; | 23 | const math = std.math; |
| 23 | const ziggurat = @import("rand/ziggurat.zig"); | 24 | const ziggurat = @import("rand/ziggurat.zig"); |
| ... | @@ -935,6 +936,105 @@ test "isaac64 sequence" { | ... | @@ -935,6 +936,105 @@ test "isaac64 sequence" { |
| 935 | } | 936 | } |
| 936 | } | 937 | } |
| 937 | 938 | ||
| 939 | /// Sfc64 pseudo-random number generator from Practically Random. | ||
| 940 | /// Fastest engine of pracrand and smallest footprint. | ||
| 941 | /// See http://pracrand.sourceforge.net/ | ||
| 942 | pub const Sfc64 = struct { | ||
| 943 | random: Random, | ||
| 944 | |||
| 945 | a: u64 = undefined, | ||
| 946 | b: u64 = undefined, | ||
| 947 | c: u64 = undefined, | ||
| 948 | counter: u64 = undefined, | ||
| 949 | |||
| 950 | const Rotation = 24; | ||
| 951 | const RightShift = 11; | ||
| 952 | const LeftShift = 3; | ||
| 953 | |||
| 954 | pub fn init(init_s: u64) Sfc64 { | ||
| 955 | var x = Sfc64{ | ||
| 956 | .random = Random{ .fillFn = fill }, | ||
| 957 | }; | ||
| 958 | |||
| 959 | x.seed(init_s); | ||
| 960 | return x; | ||
| 961 | } | ||
| 962 | |||
| 963 | fn next(self: *Sfc64) u64 { | ||
| 964 | const tmp = self.a +% self.b +% self.counter; | ||
| 965 | self.counter += 1; | ||
| 966 | self.a = self.b ^ (self.b >> RightShift); | ||
| 967 | self.b = self.c +% (self.c << LeftShift); | ||
| 968 | self.c = math.rotl(u64, self.c, Rotation) +% tmp; | ||
| 969 | return tmp; | ||
| 970 | } | ||
| 971 | |||
| 972 | fn seed(self: *Sfc64, init_s: u64) void { | ||
| 973 | self.a = init_s; | ||
| 974 | self.b = init_s; | ||
| 975 | self.c = init_s; | ||
| 976 | self.counter = 1; | ||
| 977 | var i: u32 = 0; | ||
| 978 | while (i < 12) : (i += 1) { | ||
| 979 | _ = self.next(); | ||
| 980 | } | ||
| 981 | } | ||
| 982 | |||
| 983 | fn fill(r: *Random, buf: []u8) void { | ||
| 984 | const self = @fieldParentPtr(Sfc64, "random", r); | ||
| 985 | |||
| 986 | var i: usize = 0; | ||
| 987 | const aligned_len = buf.len - (buf.len & 7); | ||
| 988 | |||
| 989 | // Complete 8 byte segments. | ||
| 990 | while (i < aligned_len) : (i += 8) { | ||
| 991 | var n = self.next(); | ||
| 992 | comptime var j: usize = 0; | ||
| 993 | inline while (j < 8) : (j += 1) { | ||
| 994 | buf[i + j] = @truncate(u8, n); | ||
| 995 | n >>= 8; | ||
| 996 | } | ||
| 997 | } | ||
| 998 | |||
| 999 | // Remaining. (cuts the stream) | ||
| 1000 | if (i != buf.len) { | ||
| 1001 | var n = self.next(); | ||
| 1002 | while (i < buf.len) : (i += 1) { | ||
| 1003 | buf[i] = @truncate(u8, n); | ||
| 1004 | n >>= 8; | ||
| 1005 | } | ||
| 1006 | } | ||
| 1007 | } | ||
| 1008 | }; | ||
| 1009 | |||
| 1010 | test "Sfc64 sequence" { | ||
| 1011 | // Unfortunately there does not seem to be an official test sequence. | ||
| 1012 | var r = Sfc64.init(0); | ||
| 1013 | |||
| 1014 | const seq = []const u64{ | ||
| 1015 | 0x3acfa029e3cc6041, | ||
| 1016 | 0xf5b6515bf2ee419c, | ||
| 1017 | 0x1259635894a29b61, | ||
| 1018 | 0xb6ae75395f8ebd6, | ||
| 1019 | 0x225622285ce302e2, | ||
| 1020 | 0x520d28611395cb21, | ||
| 1021 | 0xdb909c818901599d, | ||
| 1022 | 0x8ffd195365216f57, | ||
| 1023 | 0xe8c4ad5e258ac04a, | ||
| 1024 | 0x8f8ef2c89fdb63ca, | ||
| 1025 | 0xf9865b01d98d8e2f, | ||
| 1026 | 0x46555871a65d08ba, | ||
| 1027 | 0x66868677c6298fcd, | ||
| 1028 | 0x2ce15a7e6329f57d, | ||
| 1029 | 0xb2f1833ca91ca79, | ||
| 1030 | 0x4b0890ac9bf453ca, | ||
| 1031 | }; | ||
| 1032 | |||
| 1033 | for (seq) |s| { | ||
| 1034 | expectEqual(s, r.next()); | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | |||
| 938 | // Actual Random helper function tests, pcg engine is assumed correct. | 1038 | // Actual Random helper function tests, pcg engine is assumed correct. |
| 939 | test "Random float" { | 1039 | test "Random float" { |
| 940 | var prng = DefaultPrng.init(0); | 1040 | var prng = DefaultPrng.init(0); |