RandLib 2.0.0
Probability distributions, fitting, and heavy-tail tools for C++20
Loading...
Searching...
No Matches
engine/uniform.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <bit>
4#include <cmath>
5#include <concepts>
6#include <cstdint>
7#include <limits>
8#include <random>
9#include <type_traits>
10
11namespace randlib::detail
12{
13
15template <std::uniform_random_bit_generator G>
16constexpr int engineBits() noexcept
17{
18 static_assert(sizeof(typename G::result_type) <= sizeof(std::uint64_t),
19 "engines wider than 64 bits are not supported");
20 constexpr std::uint64_t range = static_cast<std::uint64_t>(G::max() - G::min());
21 if constexpr (range == std::numeric_limits<std::uint64_t>::max())
22 return 64;
23 else
24 return std::bit_width(range + 1) - 1;
25}
26
32template <std::uniform_random_bit_generator G>
33std::uint64_t randomBits(G &g, int count)
34{
35 constexpr int width = engineBits<G>();
36 constexpr std::uint64_t range = static_cast<std::uint64_t>(G::max() - G::min());
37 constexpr bool exact = width == 64 || range + 1 == (std::uint64_t{1} << (width % 64));
38 if constexpr (width == 64) {
39 std::uint64_t v = static_cast<std::uint64_t>(g() - G::min());
40 return count == 64 ? v : v >> (64 - count);
41 } else {
42 std::uint64_t bits = 0;
43 int filled = 0;
44 while (filled < count) {
45 std::uint64_t v = static_cast<std::uint64_t>(g() - G::min());
46 if constexpr (!exact) {
47 if (v >> width)
48 continue;
49 }
50 bits = (bits << width) | v;
51 filled += width;
52 }
53 int available = filled < 64 ? filled : 64;
54 return count == 64 ? bits : bits >> (available - count);
55 }
56}
57
62template <std::floating_point Real, std::uniform_random_bit_generator G>
64{
65 constexpr int b = std::numeric_limits<Real>::digits - 1;
66 if constexpr (b <= 64) {
67 Real k = static_cast<Real>(randomBits(g, b));
68 return std::ldexp(k + static_cast<Real>(0.5), -b);
69 } else {
70 Real high = static_cast<Real>(randomBits(g, 64));
71 Real low = static_cast<Real>(randomBits(g, b - 64));
72 return std::ldexp(std::ldexp(high, b - 64) + low + static_cast<Real>(0.5), -b);
73 }
74}
75
77template <std::floating_point Real, std::uniform_random_bit_generator G>
79{
80 constexpr int b = std::numeric_limits<Real>::digits < 64 ? std::numeric_limits<Real>::digits : 64;
81 Real k = static_cast<Real>(randomBits(g, b));
82 return k / (std::ldexp(static_cast<Real>(1), b) - 1);
83}
84
86template <std::floating_point Real, std::uniform_random_bit_generator G>
88{
89 constexpr int b = std::numeric_limits<Real>::digits < 64 ? std::numeric_limits<Real>::digits : 64;
90 Real k = static_cast<Real>(randomBits(g, b));
91 return std::ldexp(k, -b);
92}
93
99template <std::uniform_random_bit_generator G>
100std::uint64_t uniformBelow(G &g, std::uint64_t n)
101{
102 const std::uint64_t threshold = (0 - n) % n;
103 std::uint64_t v = randomBits(g, 64);
104 while (v < threshold)
105 v = randomBits(g, 64);
106 return v % n;
107}
108
116{
117public:
118 using result_type = std::uint64_t;
119
120 template <std::uniform_random_bit_generator G>
121 requires(!std::same_as<std::remove_cv_t<G>, EngineRef>)
122 EngineRef(G &engine) noexcept : target(&engine), next([](void *e) { return randomBits(*static_cast<G *>(e), 64); })
123 {
124 }
125
126 static constexpr result_type min() noexcept { return 0; }
127 static constexpr result_type max() noexcept { return ~result_type{0}; }
128
129 result_type operator()() { return next(target); }
130
131private:
132 void *target;
133 result_type (*next)(void *);
134};
135
136} // namespace randlib::detail
The EngineRef class Non-owning, type-erased reference to any uniform random bit generator.
Definition engine/uniform.hpp:116
result_type operator()()
Definition engine/uniform.hpp:129
std::uint64_t result_type
Definition engine/uniform.hpp:118
static constexpr result_type min() noexcept
Definition engine/uniform.hpp:126
EngineRef(G &engine) noexcept
Definition engine/uniform.hpp:122
static constexpr result_type max() noexcept
Definition engine/uniform.hpp:127
Definition stable.hpp:18
std::uint64_t uniformBelow(G &g, std::uint64_t n)
Definition engine/uniform.hpp:100
Real uniform01Closed(G &g)
k / (2^b - 1) for b = min(digits, 64) random bits: uniform on [0, 1]
Definition engine/uniform.hpp:78
Real uniform01HalfClosed(G &g)
k / 2^b for b = min(digits, 64) random bits: uniform on [0, 1)
Definition engine/uniform.hpp:87
std::uint64_t randomBits(G &g, int count)
Definition engine/uniform.hpp:33
Real uniform01(G &g)
Definition engine/uniform.hpp:63
constexpr int engineBits() noexcept
Number of uniformly distributed bits in one output of G: floor(log2(max - min + 1))
Definition engine/uniform.hpp:16
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45