-
-
Save briancavalier/f71314fcff5e7870608e to your computer and use it in GitHub Desktop.
Pure, splittable version of BurtlePRNG
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
// BurtlePRNG ported from https://github.com/graue/burtleprng | |
// Immutable + splittable + ES2015 by @briancavalier | |
// newRandom :: UInt32 -> UInt32 -> UInt32 -> UInt32 -> Gen a | |
// Create a new prng with exact state | |
export const newRandom = (s0, s1, s2, s3) => | |
new BurtlePRNG(s0>>>0, s1>>>0, s2>>>0, s3>>>0); | |
// seedRandom :: UInt32 -> Gen a | |
// Create a new prng from a 32-bit int seed | |
export const seedRandom = seed => { | |
const s123 = seed >>> 0; | |
return prime(20, new BurtlePRNG(S0, s123, s123, s123)); | |
} | |
// splitn :: Int -> Gen a -> [Gen a] | |
// Create n new distinct, but deterministic prngs based on g | |
// Ugly imperative impl for speed | |
export const splitn = (n, g) => { | |
const a = new Array(n); | |
for(let i = 0; i < n; ++i) { | |
const { value, next } = g.next(); | |
a[i] = next; | |
g = seedRandom(value); | |
} | |
return a; | |
} | |
// prime :: Int -> Gen a -> Gen a | |
// Consume n randoms to "prime" prng | |
// Ugly imperative impl for speed | |
const prime = (n, g) => { | |
for (let i = 0; i < n; ++i) { | |
const { value, next } = g.next(); | |
g = next; | |
} | |
return g; | |
}; | |
const rot = (x, k) => (x << k) | (x >> (32-k)); | |
const S0 = 0xf1ea5eed; | |
const REAL_DIVISOR = 4294967296.0; | |
class BurtlePRNG { | |
constructor(s0, s1, s2, s3) { | |
this.s0 = s0; | |
this.s1 = s1; | |
this.s2 = s2; | |
this.s3 = s3; | |
} | |
next() { | |
const e = (this.s0 - rot(this.s1, 27))>>>0; | |
const s0 = (this.s1 ^ rot(this.s2, 17))>>>0; | |
const s1 = (this.s2 + this.s3)>>>0; | |
const s2 = (this.s3 + e)>>>0; | |
const s3 = (e + s0)>>>0; | |
return { value: s3, next: new BurtlePRNG(s0, s1, s2, s3) }; | |
} | |
nextReal() { | |
const { value, next } = this.next(); | |
return { value: value/REAL_DIVISOR, next }; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment