Static `Lemire rejection` function called by random_bounded_uint64(...) */
| 1188 | |
| 1189 | /* Static `Lemire rejection` function called by random_bounded_uint64(...) */ |
| 1190 | static inline uint64_t bounded_lemire_uint64(bitgen_t *bitgen_state, |
| 1191 | uint64_t rng) { |
| 1192 | /* |
| 1193 | * Uses Lemire's algorithm - https://arxiv.org/abs/1805.10941 |
| 1194 | * |
| 1195 | * Note: `rng` should not be 0xFFFFFFFFFFFFFFFF. When this happens `rng_excl` |
| 1196 | * becomes zero. |
| 1197 | */ |
| 1198 | const uint64_t rng_excl = rng + 1; |
| 1199 | |
| 1200 | assert(rng != 0xFFFFFFFFFFFFFFFFULL); |
| 1201 | |
| 1202 | #if __SIZEOF_INT128__ |
| 1203 | /* 128-bit uint available (e.g. GCC/clang). `m` is the __uint128_t scaled |
| 1204 | * integer. */ |
| 1205 | __uint128_t m; |
| 1206 | uint64_t leftover; |
| 1207 | |
| 1208 | /* Generate a scaled random number. */ |
| 1209 | m = ((__uint128_t)next_uint64(bitgen_state)) * rng_excl; |
| 1210 | |
| 1211 | /* Rejection sampling to remove any bias. */ |
| 1212 | leftover = m & 0xFFFFFFFFFFFFFFFFULL; |
| 1213 | |
| 1214 | if (leftover < rng_excl) { |
| 1215 | /* `rng_excl` is a simple upper bound for `threshold`. */ |
| 1216 | const uint64_t threshold = (UINT64_MAX - rng) % rng_excl; |
| 1217 | |
| 1218 | while (leftover < threshold) { |
| 1219 | m = ((__uint128_t)next_uint64(bitgen_state)) * rng_excl; |
| 1220 | leftover = m & 0xFFFFFFFFFFFFFFFFULL; |
| 1221 | } |
| 1222 | } |
| 1223 | |
| 1224 | return (m >> 64); |
| 1225 | #else |
| 1226 | /* 128-bit uint NOT available (e.g. MSVS). `m1` is the upper 64-bits of the |
| 1227 | * scaled integer. */ |
| 1228 | uint64_t m1; |
| 1229 | uint64_t x; |
| 1230 | uint64_t leftover; |
| 1231 | |
| 1232 | x = next_uint64(bitgen_state); |
| 1233 | |
| 1234 | /* Rejection sampling to remove any bias. */ |
| 1235 | leftover = x * rng_excl; /* The lower 64-bits of the mult. */ |
| 1236 | |
| 1237 | if (leftover < rng_excl) { |
| 1238 | /* `rng_excl` is a simple upper bound for `threshold`. */ |
| 1239 | const uint64_t threshold = (UINT64_MAX - rng) % rng_excl; |
| 1240 | |
| 1241 | while (leftover < threshold) { |
| 1242 | x = next_uint64(bitgen_state); |
| 1243 | leftover = x * rng_excl; |
| 1244 | } |
| 1245 | } |
| 1246 | |
| 1247 | #if defined(_MSC_VER) && defined(_WIN64) |
no test coverage detected