From c08b86b1c07bc45c14393ed0d3e759faa89ea59b Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Mon, 11 Nov 2024 18:35:57 -0700 Subject: Factor out libmisc/rand.h --- libmisc/include/libmisc/rand.h | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 libmisc/include/libmisc/rand.h (limited to 'libmisc/include') 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 + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_RAND_H_ +#define _LIBMISC_RAND_H_ + +#include /* for uint{n}_t, UINT{n}_C() */ +#include /* for random() */ + +#include + +/** + * 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_ */ -- cgit v1.2.3-2-g168b