/**
* XORShiftPlus "non-linear" PRNG
* Author: k98kurz (@gmail)
* License: MIT
* Date: 2020-09-07
* Description: Based upon the xorshift128+ generator, one of the fastest generators passing BigCrush.
* Methods:
* next(n) returns Uint32Array of n random numbers
* nextHex(n) returns Array of n hexidecimal numbers
* bytes(n) returns Uint8Array of n random bytes
* bytesHex(n) returns Array of n random bytes in hexidecimal
* hex(n) returns hexidecimal string of n bytes
* Note: This generates with higher periodicity and better random distribution than the linear XORShift.
*/
class XORShiftPlus {
#booted = false;
#x;
#y;
#z;
#w;
constructor (seed) {
this.#x = new Uint32Array(1);
this.#y = new Uint32Array(1);
this.#z = new Uint32Array(1);
this.#w = new Uint32Array(1);
this.#x[0] = seed ? seed|0 : 317973455;
this.#y[0] = this.#x[0]<<362436069;
this.#z[0] = this.#y[0]+this.#x[0];
this.#w[0] = this.#z[0]^this.#x[0]+this.#y[0];
}
#next () {
let t = new Uint32Array(1);
t[0] = this.#x[0]^(this.#x[0]<<11);
this.#x[0] = this.#y[0];
this.#y[0] = this.#z[0];
this.#z[0] = this.#w[0];
this.#w[0] = this.#w[0]^(this.#w[0]>>19)^(t[0]^(t[0]>>8));
return this.#w[0]+this.#y[0];
}
#boot () {
// if not booted, discard the first numbers as they are somewhat predictable
if (this.#booted)
return;
for (let i=0, n=this.#next(), j=this.#next()%256; i<=j; this.#next(), ++i);
this.#booted = true;
}
next (n, option) {
this.#boot();
n = (n === undefined || typeof n !== 'number') ? 1 : n;
let t; n |= 0; n = n>0 ? n : 1;
option = (option === undefined || typeof n !== 'number') ? 0 : option;
// redundant code, but improved performance
switch (option) {
// nextHex
case 1:
t = [];
for (let i=0, il=n; i<il; t[i++] = this.#next().toString(16));
break;
// bytes
case 2:
t = new Uint8Array(n);
for (let i=0, il=n; i<il; t[i++] = this.#next());
break;
// bytesHex
case 3:
t = [];
for (let i=0, il=n; i<il; t[i] = (this.#next()%256).toString(16), t[i] = t[i].length%2 ? '0'+t[i] : t[i], ++i);
break;
// hex
case 4:
t = [];
for (let i=0, il=n; i<il; t[i] = (this.#next()%256).toString(16), t[i] = t[i].length%2 ? '0'+t[i] : t[i], ++i);
t = t.join('');
break;
// next
default:
t = new Uint32Array(n);
for (let i=0, il=n; i<il; t[i++] = this.#next());
}
return t;
};
nextHex (n) { return this.next(n, 1); };
bytes (n) { return this.next(n, 2); };
bytesHex (n) { return this.next(n, 3); };
hex (n) { return this.next(n, 4); };
}
Comments