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 {...@@ -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);
290290
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}
308310
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);
314316
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}
332338
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");
18const builtin = @import("builtin");18const builtin = @import("builtin");
19const assert = std.debug.assert;19const assert = std.debug.assert;
20const expect = std.testing.expect;20const expect = std.testing.expect;
21const expectEqual = std.testing.expectEqual;
21const mem = std.mem;22const mem = std.mem;
22const math = std.math;23const math = std.math;
23const ziggurat = @import("rand/ziggurat.zig");24const ziggurat = @import("rand/ziggurat.zig");
...@@ -935,6 +936,105 @@ test "isaac64 sequence" {...@@ -935,6 +936,105 @@ test "isaac64 sequence" {
935 }936 }
936}937}
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
938// Actual Random helper function tests, pcg engine is assumed correct.1038// Actual Random helper function tests, pcg engine is assumed correct.
939test "Random float" {1039test "Random float" {
940 var prng = DefaultPrng.init(0);1040 var prng = DefaultPrng.init(0);