/* libmisc/rand.c - Non-crytpographic random-number utilities * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include /* for random() */ #include #include uint64_t rand_uint63n(uint64_t cnt) { assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0); if (cnt <= UINT64_C(1)<<31) { uint32_t fair_cnt = ((UINT32_C(1)<<31) / cnt) * cnt; uint32_t rnd; do { rnd = random(); } while (rnd >= fair_cnt); return rnd % cnt; } else if (cnt <= UINT64_C(1)<<62) { uint64_t fair_cnt = ((UINT64_C(1)<<62) / cnt) * cnt; uint64_t rnd; do { rnd = (((uint64_t)random()) << 31) | random(); } while (rnd >= fair_cnt); return rnd % cnt; } else if (cnt <= UINT64_C(1)<<63) { uint64_t fair_cnt = ((UINT64_C(1)<<63) / cnt) * cnt; uint64_t rnd; do { rnd = (((uint64_t)random()) << 62) | (((uint64_t)random()) << 31) | random(); } while (rnd >= fair_cnt); return rnd % cnt; } assert_notreached("cnt is out of bounds"); }