authorgravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2019-06-09 14:45:17+02:00
committergravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2019-06-09 15:25:21+02:00
log69d9f322ee380a0a22a1d93959f69699ea50d77d
treec5031b9e53d888fa139179a53024e4118e308111
parent8e0670198b249f44e789f4380fd17d6de918832c

implementation of the Sfc64 RNG from PractRand


1 files changed, 100 insertions(+), 0 deletions(-)

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);