blob: d1643eeee7f8602ab3b654e765d16f1c29839e72 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/* libmisc/rand.c - Non-crytpographic random-number utilities
*
* Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <stdlib.h> /* for random() */
#include <libmisc/assert.h>
#include <libmisc/rand.h>
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");
}
|