mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
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).
This commit is contained in:
parent
6d9f10ba36
commit
1f7fe97ac3
Notes:
github-actions[bot]
2025-12-01 11:02:26 +00:00
Author: https://github.com/Calme1709
Commit: 1f7fe97ac3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6707
Reviewed-by: https://github.com/AtkinsSJ ✅
Reviewed-by: https://github.com/gmta
3 changed files with 51 additions and 45 deletions
|
|
@ -97,4 +97,41 @@ u64 get_random_uniform_64(u64 max_bounds)
|
||||||
return random_value % max_bounds;
|
return random_value % max_bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XorShift128PlusRNG::XorShift128PlusRNG()
|
||||||
|
{
|
||||||
|
// Splitmix64 is used as xorshift is sensitive to being seeded with all 0s
|
||||||
|
u64 seed = get_random<u64>();
|
||||||
|
m_low = splitmix64(seed);
|
||||||
|
seed = get_random<u64>();
|
||||||
|
m_high = splitmix64(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
double XorShift128PlusRNG::get()
|
||||||
|
{
|
||||||
|
u64 value = advance() & ((1ULL << 53) - 1);
|
||||||
|
return value * (1.0 / (1ULL << 53));
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 XorShift128PlusRNG::splitmix64(u64& state)
|
||||||
|
{
|
||||||
|
u64 z = (state += 0x9e3779b97f4a7c15ULL);
|
||||||
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
|
||||||
|
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
|
||||||
|
return z ^ (z >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apparently this set of constants is better: https://stackoverflow.com/a/34432126
|
||||||
|
u64 XorShift128PlusRNG::advance()
|
||||||
|
{
|
||||||
|
u64 s1 = m_low;
|
||||||
|
u64 const s0 = m_high;
|
||||||
|
u64 const result = s0 + s1;
|
||||||
|
m_low = s0;
|
||||||
|
s1 ^= s1 << 23;
|
||||||
|
s1 ^= s1 >> 18;
|
||||||
|
s1 ^= s0 ^ (s0 >> 5);
|
||||||
|
m_high = s1;
|
||||||
|
return result + s1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
AK/Random.h
14
AK/Random.h
|
|
@ -31,6 +31,19 @@ inline T get_random()
|
||||||
u32 get_random_uniform(u32 max_bounds);
|
u32 get_random_uniform(u32 max_bounds);
|
||||||
u64 get_random_uniform_64(u64 max_bounds);
|
u64 get_random_uniform_64(u64 max_bounds);
|
||||||
|
|
||||||
|
// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
|
||||||
|
class XorShift128PlusRNG {
|
||||||
|
public:
|
||||||
|
XorShift128PlusRNG();
|
||||||
|
double get();
|
||||||
|
|
||||||
|
private:
|
||||||
|
u64 splitmix64(u64& state);
|
||||||
|
u64 advance();
|
||||||
|
u64 m_low { 0 };
|
||||||
|
u64 m_high { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Collection>
|
template<typename Collection>
|
||||||
inline void shuffle(Collection& collection)
|
inline void shuffle(Collection& collection)
|
||||||
{
|
{
|
||||||
|
|
@ -48,4 +61,5 @@ using AK::fill_with_random;
|
||||||
using AK::get_random;
|
using AK::get_random;
|
||||||
using AK::get_random_uniform;
|
using AK::get_random_uniform;
|
||||||
using AK::shuffle;
|
using AK::shuffle;
|
||||||
|
using AK::XorShift128PlusRNG;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -809,51 +809,6 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::pow)
|
||||||
return pow_impl(vm, vm.argument(0), vm.argument(1));
|
return pow_impl(vm, vm.argument(0), vm.argument(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
|
|
||||||
class XorShift128PlusRNG {
|
|
||||||
public:
|
|
||||||
XorShift128PlusRNG()
|
|
||||||
{
|
|
||||||
// Splitmix64 is used as xorshift is sensitive to being seeded with all 0s
|
|
||||||
u64 seed = Crypto::get_secure_random<u64>();
|
|
||||||
m_low = splitmix64(seed);
|
|
||||||
seed = Crypto::get_secure_random<u64>();
|
|
||||||
m_high = splitmix64(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
double get()
|
|
||||||
{
|
|
||||||
u64 value = advance() & ((1ULL << 53) - 1);
|
|
||||||
return value * (1.0 / (1ULL << 53));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
u64 splitmix64(u64& state)
|
|
||||||
{
|
|
||||||
u64 z = (state += 0x9e3779b97f4a7c15ULL);
|
|
||||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
|
|
||||||
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
|
|
||||||
return z ^ (z >> 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apparently this set of constants is better: https://stackoverflow.com/a/34432126
|
|
||||||
u64 advance()
|
|
||||||
{
|
|
||||||
u64 s1 = m_low;
|
|
||||||
u64 const s0 = m_high;
|
|
||||||
u64 const result = s0 + s1;
|
|
||||||
m_low = s0;
|
|
||||||
s1 ^= s1 << 23;
|
|
||||||
s1 ^= s1 >> 18;
|
|
||||||
s1 ^= s0 ^ (s0 >> 5);
|
|
||||||
m_high = s1;
|
|
||||||
return result + s1;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 m_low { 0 };
|
|
||||||
u64 m_high { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
Value MathObject::random_impl()
|
Value MathObject::random_impl()
|
||||||
{
|
{
|
||||||
// This function returns a Number value with positive sign, greater than or equal to +0𝔽 but strictly less than 1𝔽,
|
// This function returns a Number value with positive sign, greater than or equal to +0𝔽 but strictly less than 1𝔽,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue