mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
95 lines
2.1 KiB
JavaScript
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();
|
|
}
|
|
}
|