std.rand: Accept ints with >64 bits in uintLessThan

This commit is contained in:
e4m2 2023-08-15 12:02:24 +02:00
parent 6f129c9912
commit c0baed4a3e

View File

@ -136,22 +136,16 @@ pub const Random = struct {
pub fn uintLessThan(r: Random, comptime T: type, less_than: T) T {
comptime assert(@typeInfo(T).Int.signedness == .unsigned);
const bits = @typeInfo(T).Int.bits;
comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
assert(0 < less_than);
// Small is typically u32
const small_bits = @divTrunc(bits + 31, 32) * 32;
const Small = std.meta.Int(.unsigned, small_bits);
// Large is typically u64
const Large = std.meta.Int(.unsigned, small_bits * 2);
// adapted from:
// http://www.pcg-random.org/posts/bounded-rands.html
// "Lemire's (with an extra tweak from me)"
var x: Small = r.int(Small);
var m: Large = @as(Large, x) * @as(Large, less_than);
var l: Small = @as(Small, @truncate(m));
var x = r.int(T);
var m = math.mulWide(T, x, less_than);
var l: T = @truncate(m);
if (l < less_than) {
var t: Small = -%less_than;
var t = -%less_than;
if (t >= less_than) {
t -= less_than;
@ -160,12 +154,12 @@ pub const Random = struct {
}
}
while (l < t) {
x = r.int(Small);
m = @as(Large, x) * @as(Large, less_than);
l = @as(Small, @truncate(m));
x = r.int(T);
m = math.mulWide(T, x, less_than);
l = @truncate(m);
}
}
return @as(T, @intCast(m >> small_bits));
return @intCast(m >> bits);
}
/// Constant-time implementation off `uintAtMost`.