Files
meteor/packages/random/AleaRandomGenerator.js
2020-02-25 10:39:44 +01:00

95 lines
2.1 KiB
JavaScript

import RandomGenerator from './AbstractRandomGenerator';
// Alea PRNG, which is not cryptographically strong
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript
// for a full discussion and Alea implementation.
function Alea(seeds) {
function Mash() {
let n = 0xefc8249d;
const mash = (data) => {
data = data.toString();
for (let i = 0; i < data.length; i++) {
n += data.charCodeAt(i);
let h = 0.02519603282416938 * n;
n = h >>> 0;
h -= n;
h *= n;
n = h >>> 0;
h -= n;
n += h * 0x100000000; // 2^32
}
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
};
mash.version = 'Mash 0.9';
return mash;
}
let s0 = 0;
let s1 = 0;
let s2 = 0;
let c = 1;
if (seeds.length === 0) {
seeds = [+new Date];
}
let mash = Mash();
s0 = mash(' ');
s1 = mash(' ');
s2 = mash(' ');
for (let i = 0; i < seeds.length; i++) {
s0 -= mash(seeds[i]);
if (s0 < 0) {
s0 += 1;
}
s1 -= mash(seeds[i]);
if (s1 < 0) {
s1 += 1;
}
s2 -= mash(seeds[i]);
if (s2 < 0) {
s2 += 1;
}
}
mash = null;
const random = () => {
const t = (2091639 * s0) + (c * 2.3283064365386963e-10); // 2^-32
s0 = s1;
s1 = s2;
return s2 = t - (c = t | 0);
};
random.uint32 = () => random() * 0x100000000; // 2^32
random.fract53 = () => random() +
((random() * 0x200000 | 0) * 1.1102230246251565e-16); // 2^-53
random.version = 'Alea 0.9';
random.args = seeds;
return random;
}
// options:
// - seeds: an array
// whose items will be `toString`ed and used as the seed to the Alea
// algorithm
export default class AleaRandomGenerator extends RandomGenerator {
constructor ({ seeds = [] } = {}) {
super();
if (!seeds) {
throw new Error('No seeds were provided for Alea PRNG');
}
this.alea = Alea(seeds);
}
/**
* @name Random.fraction
* @summary Return a number between 0 and 1, like `Math.random`.
* @locus Anywhere
*/
fraction () {
return this.alea();
}
}