summaryrefslogtreecommitdiff
path: root/libmisc/rand.c
blob: bd235233d75fa2d375bc1d616e8ad0fc262e7a96 (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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* 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 <libmisc/assert.h>

#include <libmisc/_intercept.h>
#include <libmisc/rand.h>

uint32_t rand_uint32(void) {
	return __lm_rand_uint32();
}

uint64_t rand_uint64(void) {
	return __lm_rand_uint64();
}

uint32_t rand_uint31n(uint32_t cnt) {
	assert(cnt != 0 && ((cnt-1) & 0x80000000) == 0);
	uint32_t fair_cnt = ((UINT32_C(1)<<31) / cnt) * cnt;
	uint32_t rnd;
	do {
		rnd = __lm_rand_uint31();
	} while (rnd >= fair_cnt);
	return rnd % cnt;
}

uint64_t rand_uint63n(uint64_t cnt) {
	assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0);
	if (cnt <= UINT64_C(1)<<31) {
		return rand_uint31n(cnt);
	} else if (cnt <= UINT64_C(1)<<32) {
		uint64_t fair_cnt = ((UINT64_C(1)<<32) / cnt) * cnt;
		uint64_t rnd;
		do {
			rnd = __lm_rand_uint32();
		} 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 = __lm_rand_uint62();
		} while (rnd >= fair_cnt);
		return rnd % cnt;
	} else {
		uint64_t fair_cnt = ((UINT64_C(1)<<63) / cnt) * cnt;
		uint64_t rnd;
		do {
			rnd = __lm_rand_uint63();
		} while (rnd >= fair_cnt);
		return rnd % cnt;
	}
}