Last active
September 20, 2018 16:30
-
-
Save nestordemeure/6a666b5787a3985de59d9fe582264ac3 to your computer and use it in GitHub Desktop.
Xorshift128+ : quick yet high quality 64-bit pseudo random number generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
The Xorshift128+ generator generates a high-quality 64-bit value very quickly (see reference). | |
It is presently used in the JavaScript engines of Chrome, Firefox and Safari, and it is the default generator in Erlang. | |
If you find its period too short for large-scale parallel simulations, use xorshift1024*. | |
Note that the lowest bit of this generator is an LSFR, | |
and thus it is slightly less random than the other bits. | |
We suggest to use a sign test to extract a random Boolean value. | |
Reference : http://xoroshiro.di.unimi.it/ | |
http://xoroshiro.di.unimi.it/xorshift128plus.c | |
*) | |
namespace Random | |
open System | |
/// The Xorshift128+ generator generates a high-quality 64-bit value very quickly | |
/// The state must be seeded so that it is not everywhere zero. | |
type Xorshift128plus(seed0,seed1) = | |
let mutable seed0 = seed0 | |
let mutable seed1 = seed1 | |
/// The Xorshift128+ generator generates a high-quality 64-bit value very quickly | |
new() = | |
// If you have a 64-bit seed, we suggest to seed a splitmix64 generator. | |
let stdRng = Random() | |
let seed0 = stdRng.Next() |> uint64 | |
let seed1 = stdRng.Next() |> uint64 | |
// The state must be seeded so that it is not everywhere zero. | |
if seed0 = 0UL && seed1 = 0UL then Xorshift128plus() else | |
Xorshift128plus(seed0,seed1) | |
//--------- | |
/// Produce a pseudo-random uint64 between 0 and UInt64.MaxValue, update the generator | |
member this.NextUInt64() = | |
let result = seed1 + seed0 | |
let s1 = seed0 ^^^ (seed0 <<< 23) // a | |
seed0 <- seed1 | |
seed1 <- s1 ^^^ seed1 ^^^ (s1 >>> 18) ^^^ (seed1 >>> 5) // b, c | |
result | |
/// Produce a pseudo-random int32 between 0 and Int.MaxValue, update the generator | |
member this.NextInt() = | |
let k = this.NextUInt64() | |
int (k / 8589934596UL) // UInt64.MaxValue / Int32.MaxValue | |
/// Produce a pseudo-random int32 between 0 and borneSup, update the generator | |
member this.NextInt(borneSup) = | |
let k = this.NextUInt64() | |
k * ( (uint64 borneSup) / 8589934596UL) |> int // UInt64.MaxValue / Int32.MaxValue | |
/// Produce a pseudo-random float between 0 and 1, update the generator | |
member this.NextFloat() = | |
let k = this.NextUInt64() | |
(float k) / 18446744073709551615. // UInt64.MaxValue | |
/// Produce a pseudo-random float between 0 and borneSup, update the generator | |
member this.NextFloat(borneSup) = | |
let k = this.NextUInt64() | |
(float k) * (borneSup / 18446744073709551615.) // UInt64.MaxValue | |
/// Produce a pseudo-random bool, update the generator | |
member this.NextBool() = | |
let k = this.NextUInt64() | |
k > 9223372036854775807UL // UInt64.MaxValue / 2UL | |
/// Produce a pseudo-random bool with a given probability, update the generator | |
member this.NextBool(trueProba) = | |
this.NextFloat() < trueProba | |
//---------- | |
/// Equivalent to 2^64 call to next | |
/// Can be used to generate 2^64 non-overlapping subsequences for parallel computations. | |
member this.Jump() = | |
let jump = [|9970080660168977919UL; 1305993406145048470UL|] // 0x8a5cd789635d2dff, 0x121fd2155c472f96 | |
let mutable s0 = 0UL | |
let mutable s1 = 0UL | |
for i = 0 to 1 do | |
for b = 0 to 63 do | |
if (jump.[i] &&& 1UL <<< b) = 1UL then | |
s0 <- s0 ^^^ seed0 | |
s1 <- s1 ^^^ seed1 | |
this.NextUInt64() |> ignore | |
seed0 <- s0 | |
seed1 <- s1 | |
/// Create a new generator identical to the current generator | |
member this.Copy() = Xorshift128plus(seed0,seed1) | |
/// Create n non overlapping generators | |
/// Can be used to generate up to 2^64 non-overlapping subsequences for parallel computations. | |
static member CreateNonOverlapping n = | |
let gen = Xorshift128plus() | |
Array.init n (fun _ -> gen.Jump() ; gen.Copy() ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment