1 | #pragma once |
2 | |
3 | #include "basis/seadRawPrint.h" |
4 | #include "basis/seadTypes.h" |
5 | #include "prim/seadBitUtil.h" |
6 | |
7 | namespace sead |
8 | { |
9 | /// A fast non-cryptographically secure pseudorandom number generator based on Xorshift128. |
10 | class Random |
11 | { |
12 | public: |
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 | |
52 | private: |
53 | u32 mX; |
54 | u32 mY; |
55 | u32 mZ; |
56 | u32 mW; |
57 | }; |
58 | |
59 | inline u32 Random::getU32(u32 max) |
60 | { |
61 | return getU32() * u64(max) >> 32u; |
62 | } |
63 | |
64 | inline 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 |
71 | inline 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 | |
77 | inline f32 Random::getF32() |
78 | { |
79 | return BitUtil::bitCast<f32>((getU32() >> 9u) | 0x3F800000u) - 1.0f; |
80 | } |
81 | |
82 | inline 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 |
89 | inline f64 Random::getF64() |
90 | { |
91 | return BitUtil::bitCast<f64>((getU64() >> 12u) | 0x3FF0'0000'0000'0000lu) - 1.0; |
92 | } |
93 | |
94 | // UNCHECKED |
95 | inline 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 |
102 | inline bool Random::getBool() |
103 | { |
104 | return getU32() & 0x80000000u; |
105 | } |
106 | |
107 | } // namespace sead |
108 | |