diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-11-11 18:35:57 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-11-11 19:19:48 -0700 |
commit | c08b86b1c07bc45c14393ed0d3e759faa89ea59b (patch) | |
tree | 21404cdc25798996acc2113d3ccc7806e28afdf5 /libmisc | |
parent | 9f6f267cc4acb6c72872e42593ca701df1f5fdc3 (diff) |
Factor out libmisc/rand.h
Diffstat (limited to 'libmisc')
-rw-r--r-- | libmisc/include/libmisc/rand.h | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/libmisc/include/libmisc/rand.h b/libmisc/include/libmisc/rand.h new file mode 100644 index 0000000..bdb0db9 --- /dev/null +++ b/libmisc/include/libmisc/rand.h @@ -0,0 +1,46 @@ +/* libmisc/rand.h - Non-crytpographic random-number utilities + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_RAND_H_ +#define _LIBMISC_RAND_H_ + +#include <stdint.h> /* for uint{n}_t, UINT{n}_C() */ +#include <stdlib.h> /* for random() */ + +#include <libmisc/assert.h> + +/** + * Return a psuedo-random number in the half-open interval [0,cnt). + * `cnt` must not be greater than 1<<63. + */ +static inline uint64_t rand_uint63n(uint64_t cnt) { + 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 = (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 = (random() << 62) | (random() << 31) | random(); + } while (rnd >= fair_cnt); + return rnd % cnt; + } else { + assert_notreached("cnt is out of bounds"); + } +} + +#endif /* _LIBMISC_RAND_H_ */ |