1#pragma once
2
3#include "basis/seadRawPrint.h"
4#include "basis/seadTypes.h"
5#include "prim/seadBitUtil.h"
6
7namespace sead
8{
9/// A fast non-cryptographically secure pseudorandom number generator based on Xorshift128.
10class Random
11{
12public:
13 Random() { init(); }
14 Random(u32 seed) { init(seed); }
15 /// @warning Parameters have to be chosen carefully to get a long period. Using this is not
16 /// recommended.
17 Random(u32 seed_x, u32 seed_y, u32 seed_z, u32 seed_w) { init(seed_x, seed_y, seed_z, seed_w); }
18
19 /// Reset and seed the engine with the current system tick count.
20 void init();
21 /// Reset and seed the engine with the specified value.
22 void init(u32 seed);
23 /// @warning Parameters have to be chosen carefully to get a long period. Using this is not
24 /// recommended.
25 void init(u32 seed_x, u32 seed_y, u32 seed_z, u32 seed_w);
26
27 /// Generate a random u32.
28 u32 getU32();
29 /// Generate a random u64.
30 u64 getU64();
31 /// Generate a random u32 in [0 .. max).
32 u32 getU32(u32 max);
33 /// Generate a random s32 in [a .. b).
34 /// Note that this does not provide a uniform distribution.
35 s32 getS32Range(s32 a, s32 b);
36 /// Generate a random s64 in [a .. b).
37 /// Note that this does not provide a uniform distribution.
38 s64 getS64Range(s64 a, s64 b);
39 /// Generate a random f32 in [0, 1).
40 f32 getF32();
41 /// Generate a random f32 in [a, b).
42 f32 getF32Range(f32 a, f32 b);
43 /// Generate a random f64 in [0, 1).
44 f64 getF64();
45 /// Generate a random f64 in [a, b).
46 f64 getF64Range(f64 a, f64 b);
47 /// Generate a random boolean.
48 bool getBool();
49
50 void getContext(u32* x, u32* y, u32* z, u32* w) const;
51
52private:
53 u32 mX;
54 u32 mY;
55 u32 mZ;
56 u32 mW;
57};
58
59inline u32 Random::getU32(u32 max)
60{
61 return getU32() * u64(max) >> 32u;
62}
63
64inline s32 Random::getS32Range(s32 a, s32 b)
65{
66 SEAD_ASSERT_MSG(a <= b, "b[%d] >= a[%d]", a, b);
67 return getU32(b - a) + static_cast<u32>(a);
68}
69
70// UNCHECKED
71inline s64 Random::getS64Range(s64 a, s64 b)
72{
73 SEAD_ASSERT_MSG(a <= b, "b[%ld] >= a[%ld]", a, b);
74 return (getU32() * u64(b - a) >> 32u) + a;
75}
76
77inline f32 Random::getF32()
78{
79 return BitUtil::bitCast<f32>((getU32() >> 9u) | 0x3F800000u) - 1.0f;
80}
81
82inline f32 Random::getF32Range(f32 a, f32 b)
83{
84 SEAD_ASSERT_MSG(a <= b, "b[%f] >= a[%f]", a, b);
85 return a + (b - a) * getF32();
86}
87
88// UNCHECKED
89inline f64 Random::getF64()
90{
91 return BitUtil::bitCast<f64>((getU64() >> 12u) | 0x3FF0'0000'0000'0000lu) - 1.0;
92}
93
94// UNCHECKED
95inline f64 Random::getF64Range(f64 a, f64 b)
96{
97 SEAD_ASSERT_MSG(a <= b, "b[%f] >= a[%f]", a, b);
98 return a + (b - a) * getF64();
99}
100
101// UNCHECKED
102inline bool Random::getBool()
103{
104 return getU32() & 0x80000000u;
105}
106
107} // namespace sead
108