Skip to content

Commit 1f7fe97

Browse files
Calme1709AtkinsSJ
authored andcommitted
LibJS/AK: Move XorShift128PlusRNG to AK
This will be useful for CSS random functions so it should be in a reusable place. This does require us to use `AK::get_random` instead of `Crypto::get_secure_random`, but this is fine since the latter is in the process of being removed (see #6564).
1 parent 6d9f10b commit 1f7fe97

File tree

3 files changed

+51
-45
lines changed

3 files changed

+51
-45
lines changed

AK/Random.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,41 @@ u64 get_random_uniform_64(u64 max_bounds)
9797
return random_value % max_bounds;
9898
}
9999

100+
XorShift128PlusRNG::XorShift128PlusRNG()
101+
{
102+
// Splitmix64 is used as xorshift is sensitive to being seeded with all 0s
103+
u64 seed = get_random<u64>();
104+
m_low = splitmix64(seed);
105+
seed = get_random<u64>();
106+
m_high = splitmix64(seed);
107+
}
108+
109+
double XorShift128PlusRNG::get()
110+
{
111+
u64 value = advance() & ((1ULL << 53) - 1);
112+
return value * (1.0 / (1ULL << 53));
113+
}
114+
115+
u64 XorShift128PlusRNG::splitmix64(u64& state)
116+
{
117+
u64 z = (state += 0x9e3779b97f4a7c15ULL);
118+
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
119+
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
120+
return z ^ (z >> 31);
121+
}
122+
123+
// Apparently this set of constants is better: https://stackoverflow.com/a/34432126
124+
u64 XorShift128PlusRNG::advance()
125+
{
126+
u64 s1 = m_low;
127+
u64 const s0 = m_high;
128+
u64 const result = s0 + s1;
129+
m_low = s0;
130+
s1 ^= s1 << 23;
131+
s1 ^= s1 >> 18;
132+
s1 ^= s0 ^ (s0 >> 5);
133+
m_high = s1;
134+
return result + s1;
135+
}
136+
100137
}

AK/Random.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ inline T get_random()
3131
u32 get_random_uniform(u32 max_bounds);
3232
u64 get_random_uniform_64(u64 max_bounds);
3333

34+
// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
35+
class XorShift128PlusRNG {
36+
public:
37+
XorShift128PlusRNG();
38+
double get();
39+
40+
private:
41+
u64 splitmix64(u64& state);
42+
u64 advance();
43+
u64 m_low { 0 };
44+
u64 m_high { 0 };
45+
};
46+
3447
template<typename Collection>
3548
inline void shuffle(Collection& collection)
3649
{
@@ -48,4 +61,5 @@ using AK::fill_with_random;
4861
using AK::get_random;
4962
using AK::get_random_uniform;
5063
using AK::shuffle;
64+
using AK::XorShift128PlusRNG;
5165
#endif

Libraries/LibJS/Runtime/MathObject.cpp

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -809,51 +809,6 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::pow)
809809
return pow_impl(vm, vm.argument(0), vm.argument(1));
810810
}
811811

812-
// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
813-
class XorShift128PlusRNG {
814-
public:
815-
XorShift128PlusRNG()
816-
{
817-
// Splitmix64 is used as xorshift is sensitive to being seeded with all 0s
818-
u64 seed = Crypto::get_secure_random<u64>();
819-
m_low = splitmix64(seed);
820-
seed = Crypto::get_secure_random<u64>();
821-
m_high = splitmix64(seed);
822-
}
823-
824-
double get()
825-
{
826-
u64 value = advance() & ((1ULL << 53) - 1);
827-
return value * (1.0 / (1ULL << 53));
828-
}
829-
830-
private:
831-
u64 splitmix64(u64& state)
832-
{
833-
u64 z = (state += 0x9e3779b97f4a7c15ULL);
834-
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
835-
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
836-
return z ^ (z >> 31);
837-
}
838-
839-
// Apparently this set of constants is better: https://stackoverflow.com/a/34432126
840-
u64 advance()
841-
{
842-
u64 s1 = m_low;
843-
u64 const s0 = m_high;
844-
u64 const result = s0 + s1;
845-
m_low = s0;
846-
s1 ^= s1 << 23;
847-
s1 ^= s1 >> 18;
848-
s1 ^= s0 ^ (s0 >> 5);
849-
m_high = s1;
850-
return result + s1;
851-
}
852-
853-
u64 m_low { 0 };
854-
u64 m_high { 0 };
855-
};
856-
857812
Value MathObject::random_impl()
858813
{
859814
// This function returns a Number value with positive sign, greater than or equal to +0𝔽 but strictly less than 1𝔽,

0 commit comments

Comments
 (0)