70 lines
1.7 KiB
JavaScript
70 lines
1.7 KiB
JavaScript
const MersenneTwister = require('./twister');
|
|
|
|
function PRNG(seed) {
|
|
this.mt = new MersenneTwister(seed);
|
|
return this;
|
|
};
|
|
|
|
PRNG.prototype.value = function() {
|
|
return this.mt.random();
|
|
};
|
|
|
|
PRNG.prototype.range = function(min, max) {
|
|
return Math.floor(this.value() * (max - min + 1) + min);
|
|
};
|
|
|
|
PRNG.prototype.realRange = function(min, max, skew_function) {
|
|
var v = this.value();
|
|
if (typeof skew_function === 'function') {
|
|
v = skew_function(v);
|
|
}
|
|
return v * (max - min) + min;
|
|
};
|
|
|
|
PRNG.prototype.gaussrandom = function(dev) {
|
|
var X;
|
|
var context = this.gaussrandom.context;
|
|
if (context === undefined) {
|
|
context = this.gaussrandom.context = {
|
|
phase: 0
|
|
};
|
|
};
|
|
if (context.phase === 0) {
|
|
do {
|
|
context.V1 = this.realRange(-1, 1);
|
|
context.V2 = this.realRange(-1, 1);
|
|
context.S = context.V1 * context.V1 + context.V2 * context.V2;
|
|
} while (context.S >= 1 || context.S == 0);
|
|
X = context.V1 * Math.sqrt(-2 * Math.log(context.S) / context.S);
|
|
} else {
|
|
X = context.V2 * Math.sqrt(-2 * Math.log(context.S) / context.S);
|
|
}
|
|
context.phase = 1 - context.phase;
|
|
if (dev === undefined) {
|
|
dev = 1.0;
|
|
}
|
|
return X * dev;
|
|
};
|
|
|
|
PRNG.prototype.pick = function(a, weights) {
|
|
var s = 0,
|
|
idx;
|
|
if (weights !== undefined) {
|
|
for (idx = 0; idx < weights.length; idx++) {
|
|
s += weights[idx];
|
|
}
|
|
s = this.value() * s;
|
|
for (idx = 0; idx < weights.length; idx++) {
|
|
s -= weights[idx];
|
|
if (s < 0) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
idx = this.range(0, a.length - 1);
|
|
}
|
|
return a[idx];
|
|
};
|
|
|
|
module.exports = PRNG;
|