authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-10 00:38:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-10 00:38:58-04:00
logaf35b73b9929b9d7a698101190b6f0d27ce27542
tree0ec91063a9bcf72f48ab36487813c5013c2ed820
parent5017a1d895847df6cc02dc4bedd02aa341177171
parent69d9f322ee380a0a22a1d93959f69699ea50d77d
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'sfc64' of https://github.com/Sahnvour/zig into Sahnvour-sfc64


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 {
288288 const abs_shift_amt = absCast(shift_amt);
289289 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
290290
291 if (@typeOf(shift_amt).is_signed) {
292 if (shift_amt >= 0) {
293 return a << casted_shift_amt;
294 } else {
291 if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) {
292 if (shift_amt < 0) {
295293 return a >> casted_shift_amt;
296294 }
297295 }
......@@ -304,6 +302,10 @@ test "math.shl" {
304302 testing.expect(shl(u8, 0b11111111, usize(8)) == 0);
305303 testing.expect(shl(u8, 0b11111111, usize(9)) == 0);
306304 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);
307309}
308310
309311/// Shifts right. Overflowed bits are truncated.
......@@ -312,7 +314,7 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T {
312314 const abs_shift_amt = absCast(shift_amt);
313315 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
314316
315 if (@typeOf(shift_amt).is_signed) {
317 if (@typeOf(shift_amt) == comptime_int or @typeOf(shift_amt).is_signed) {
316318 if (shift_amt >= 0) {
317319 return a >> casted_shift_amt;
318320 } else {
......@@ -328,6 +330,10 @@ test "math.shr" {
328330 testing.expect(shr(u8, 0b11111111, usize(8)) == 0);
329331 testing.expect(shr(u8, 0b11111111, usize(9)) == 0);
330332 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);
331337}
332338
333339/// Rotates right. Only unsigned values can be rotated.
std/rand.zig+100
......@@ -18,6 +18,7 @@ const std = @import("std.zig");
1818const builtin = @import("builtin");
1919const assert = std.debug.assert;
2020const expect = std.testing.expect;
21const expectEqual = std.testing.expectEqual;
2122const mem = std.mem;
2223const math = std.math;
2324const ziggurat = @import("rand/ziggurat.zig");
......@@ -935,6 +936,105 @@ test "isaac64 sequence" {
935936 }
936937}
937938
939/// Sfc64 pseudo-random number generator from Practically Random.
940/// Fastest engine of pracrand and smallest footprint.
941/// See http://pracrand.sourceforge.net/
942pub 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
1010test "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
9381038// Actual Random helper function tests, pcg engine is assumed correct.
9391039test "Random float" {
9401040 var prng = DefaultPrng.init(0);