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