| ... | @@ -136,22 +136,16 @@ pub const Random = struct { | ... | @@ -136,22 +136,16 @@ pub const Random = struct { |
| 136 | pub fn uintLessThan(r: Random, comptime T: type, less_than: T) T { | 136 | pub fn uintLessThan(r: Random, comptime T: type, less_than: T) T { |
| 137 | comptime assert(@typeInfo(T).Int.signedness == .unsigned); | 137 | comptime assert(@typeInfo(T).Int.signedness == .unsigned); |
| 138 | const bits = @typeInfo(T).Int.bits; | 138 | const bits = @typeInfo(T).Int.bits; |
| 139 | comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! | | |
| 140 | assert(0 < less_than); | 139 | assert(0 < less_than); |
| 141 | // Small is typically u32 | | |
| 142 | const small_bits = @divTrunc(bits + 31, 32) * 32; | | |
| 143 | const Small = std.meta.Int(.unsigned, small_bits); | | |
| 144 | // Large is typically u64 | | |
| 145 | const Large = std.meta.Int(.unsigned, small_bits * 2); | | |
| 146 | | 140 | |
| 147 | // adapted from: | 141 | // adapted from: |
| 148 | // http://www.pcg-random.org/posts/bounded-rands.html | 142 | // http://www.pcg-random.org/posts/bounded-rands.html |
| 149 | // "Lemire's (with an extra tweak from me)" | 143 | // "Lemire's (with an extra tweak from me)" |
| 150 | var x: Small = r.int(Small); | 144 | var x = r.int(T); |
| 151 | var m: Large = @as(Large, x) * @as(Large, less_than); | 145 | var m = math.mulWide(T, x, less_than); |
| 152 | var l: Small = @as(Small, @truncate(m)); | 146 | var l: T = @truncate(m); |
| 153 | if (l < less_than) { | 147 | if (l < less_than) { |
| 154 | var t: Small = -%less_than; | 148 | var t = -%less_than; |
| 155 | | 149 | |
| 156 | if (t >= less_than) { | 150 | if (t >= less_than) { |
| 157 | t -= less_than; | 151 | t -= less_than; |
| ... | @@ -160,12 +154,12 @@ pub const Random = struct { | ... | @@ -160,12 +154,12 @@ pub const Random = struct { |
| 160 | } | 154 | } |
| 161 | } | 155 | } |
| 162 | while (l < t) { | 156 | while (l < t) { |
| 163 | x = r.int(Small); | 157 | x = r.int(T); |
| 164 | m = @as(Large, x) * @as(Large, less_than); | 158 | m = math.mulWide(T, x, less_than); |
| 165 | l = @as(Small, @truncate(m)); | 159 | l = @truncate(m); |
| 166 | } | 160 | } |
| 167 | } | 161 | } |
| 168 | return @as(T, @intCast(m >> small_bits)); | 162 | return @intCast(m >> bits); |
| 169 | } | 163 | } |
| 170 | | 164 | |
| 171 | /// Constant-time implementation off `uintAtMost`. | 165 | /// Constant-time implementation off `uintAtMost`. |