From 9ae5200bd2851aab704b786f53a1495a9f58049e Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 21 Nov 2018 19:46:42 -0500 Subject: [PATCH] factor out and expose biased range limiting function --- std/rand/index.zig | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/std/rand/index.zig b/std/rand/index.zig index 055565ad65..97101bc3b7 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -63,17 +63,11 @@ pub const Random = struct { comptime assert(T.is_signed == false); comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! assert(0 < less_than); - // Small is typically u32 - const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); - // Large is typically u64 - const Large = @IntType(false, Small.bit_count * 2); - - // adapted from: - // http://www.pcg-random.org/posts/bounded-rands.html - // "Integer Multiplication (Biased)" - var x: Small = r.int(Small); - var m: Large = Large(x) * Large(less_than); - return @intCast(T, m >> Small.bit_count); + if (T.bit_count <= 32) { + return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than)); + } else { + return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); + } } /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`. /// This function assumes that the underlying ::fillFn produces evenly distributed values. @@ -276,6 +270,20 @@ pub const Random = struct { } }; +/// Convert a random integer 0 <= random_int <= maxValue(T), +/// into an integer 0 <= result < less_than. +/// This function introduces a minor bias. +pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T { + comptime assert(T.is_signed == false); + const T2 = @IntType(false, T.bit_count * 2); + + // adapted from: + // http://www.pcg-random.org/posts/bounded-rands.html + // "Integer Multiplication (Biased)" + var m: T2 = T2(random_int) * T2(less_than); + return @intCast(T, m >> T.bit_count); +} + const SequentialPrng = struct { const Self = @This(); random: Random,