MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
random.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
19#ifndef MTCORE_RANDOM_H
20#define MTCORE_RANDOM_H
21
22#include <cmath>
23#include <limits>
24
25#include "mtcore/alloc.hpp"
27#include "mtcore/core.hpp"
28#include <cstdint>
29
34
36namespace mtcore {
41 struct PrngState {
47 u8 data[32];
48 };
49
54 using SeedError = int;
55
69 struct PrngVTable {
74 uint64_t (*nextUint)(PrngState &self);
75
80 double (*next1_0)(PrngState &self);
81
86 Result<void, SeedError> (*seed)(PrngState &self, uint64_t seed);
87
93 void (*deinit)(PrngState &self);
94 };
95
100 struct Prng {
101 // State
103 // V-Table
105
109 [[nodiscard]] bool can_get1_0() const noexcept { return vtable && vtable->next1_0 != nullptr; }
110
114 [[nodiscard]] bool can_get_uint() const noexcept { return vtable && vtable->nextUint != nullptr; }
115
119 [[nodiscard]] bool can_reseed() const noexcept { return vtable && vtable->seed != nullptr; }
120
125 [[nodiscard]] double next1_0() noexcept {
126 ensure(vtable, "MISSING VTABLE FOR PRNG");
127 ensure(vtable->next1_0, "MISSING next1_0 IN PRNG VTABLE");
128 return vtable->next1_0(state);
129 }
130
135 [[nodiscard]] u64 next_uint() noexcept {
136 ensure(vtable, "MISSING VTABLE FOR PRNG");
137 ensure(vtable->nextUint, "MISSING nextUint IN PRNG VTABLE");
138 return vtable->nextUint(state);
139 }
140
148 [[nodiscard]] u64 in_range(const u64 min, const u64 max) noexcept {
149 ensure(min < max, "INVALID RANGE PROVIDED");
150 ensure(can_get_uint() || can_get1_0(), "INVALID PRNG - MUST HAVE next1_0 OR nextUint IN VTABLE");
151
152 const u64 count = max - min;
153
154 if (count == 1) {
155 return min;
156 }
157
158 const auto offset = std::numeric_limits<u64>::max() % count;
159 if (can_get_uint()) {
160 u64 res;
161 do {
162 res = next_uint();
163 } while (res >= (std::numeric_limits<u64>::max() - offset));
164 res %= count;
165 return res + min;
166 }
167 else {
168 const long double v = next1_0();
169 return static_cast<u64>(floor(v * static_cast<long double>(count))) + min;
170 }
171 }
172
180 [[nodiscard]] f64 in_range_f64(const f64 min, const f64 max) noexcept {
181 ensure(min < max, "INVALID RANGE PROVIDED");
182 ensure(can_get_uint() || can_get1_0(), "INVALID PRNG - MUST HAVE next1_0 OR nextUint IN VTABLE");
183
184 const auto count = max - min;
185
186 if (count == 1) {
187 return min;
188 }
189
190 if (can_get1_0()) {
191 const double v = next1_0();
192 return v * count + min;
193 }
194 else {
195 constexpr auto m = 10000000000;
196 const auto n = in_range(0, m);
197 const long double rng = static_cast<long double>(n) / static_cast<long double>(m);
198 return static_cast<f64>(rng * count) + min;
199 }
200 }
201
205 [[nodiscard]] Result<void, SeedError> seed(const u64 seed) noexcept {
206 ensure(vtable && vtable->seed, "INVALID VTABLE!");
207 return vtable->seed(state, seed);
208 }
209
214 void deinit() noexcept {
215 mtdefer { vtable = nullptr; };
216 if (vtable && vtable->deinit) {
217 vtable->deinit(state);
218 }
219 }
220 };
221
229 Prng tinymt_init(uint64_t seed) noexcept;
230
239 Prng lcg_init(uint64_t seed) noexcept;
240
246
257 Result<Prng, Mt19937_64Error> mt19937_64(Allocator *alloc, uint64_t seed) noexcept;
258
259} // namespace mtcore
260
261#endif // MTCORE_RANDOM_H
int SeedError
Seeding errors can vary differently, using an int to indicate the error code.
Definition random.hpp:54
Mt19937_64Error
Errors that can happen when making a Mersenne Twister.
Definition random.hpp:245
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
#define mtdefer
Defer statement that will mtdefer execution until the scope is left, at which point the code will run...
Prng lcg_init(uint64_t seed) noexcept
Initializes a Linear Congruential Generator NOTE: THIS IS NOT A GOOD PRNG (it's essentially rand())
Result< Prng, Mt19937_64Error > mt19937_64(Allocator *alloc, uint64_t seed) noexcept
Initializes a Mersenne Twister 19937-64 algorithm Note: This does require allocated memory.
Prng tinymt_init(uint64_t seed) noexcept
Initializes a PRNG based on the TinyMT variant of Mersenne Twister.
uint64_t u64
Alias for 64-bit unsigned ints.
uint8_t u8
Alias for 8-bit unsigned ints.
double f64
Alias for 64-bit floats.
Core library for C++ with Zig-related functionality.
Represents a memory allocator Exact behavior depends on the underlying VTable used Should use the a_*...
Internal PRNG state.
Definition random.hpp:41
u8 data[32]
Stack data, a 32-byte chunk of data for what a small PRNG may need How you use it is up to you If you...
Definition random.hpp:47
V-Table for PRNG Designed for having a simple PRNG implementation.
Definition random.hpp:69
double(* next1_0)(PrngState &self)
Optional Gets a double d, such that 0 <= d < 1.
Definition random.hpp:80
Result< void, SeedError >(* seed)(PrngState &self, uint64_t seed)
Optional Re-seeds the PRNG.
Definition random.hpp:86
uint64_t(* nextUint)(PrngState &self)
Optional Gets the next unsigned int.
Definition random.hpp:74
void(* deinit)(PrngState &self)
Optional Deinitializes the PRNG and frees up any allocated state The PRNG is NOT safe to use after ca...
Definition random.hpp:93
Represents a Pseudo Random Number Generator.
Definition random.hpp:100
bool can_get_uint() const noexcept
Definition random.hpp:114
Result< void, SeedError > seed(const u64 seed) noexcept
Reseeds the PRNG.
Definition random.hpp:205
u64 next_uint() noexcept
Gets the next unsigned 64-bit integer from the PRNG Will abort of canGetUInt is false!
Definition random.hpp:135
void deinit() noexcept
Deinitializes a PRNG NOTE: It is NOT safe to use a PRNG after it has been deinitialized!
Definition random.hpp:214
u64 in_range(const u64 min, const u64 max) noexcept
Gets number between min (inclusive) and max value (exclusive) Prioritizes nextUInt over next1_0.
Definition random.hpp:148
double next1_0() noexcept
Gets a number n such that $0 <= n < 1$ Will abort of canGet1_0 is false!
Definition random.hpp:125
f64 in_range_f64(const f64 min, const f64 max) noexcept
Gets number between min (inclusive) and max value (exclusive) Prioritizes next1_0 over nextUInt.
Definition random.hpp:180
bool can_reseed() const noexcept
Definition random.hpp:119
bool can_get1_0() const noexcept
Definition random.hpp:109
PrngState state
Definition random.hpp:102
const PrngVTable * vtable
Definition random.hpp:104
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Definition result.hpp:170