Skip to content

Instantly share code, notes, and snippets.

@thers
Last active December 4, 2015 11:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thers/2fab504e992cb1df3fd9 to your computer and use it in GitHub Desktop.
Save thers/2fab504e992cb1df3fd9 to your computer and use it in GitHub Desktop.
Biased random generator
function boundrand (min, max) {
return min + (Math.random() * (max - min));
}
export default class BiasedRandom {
/**
* Ctor
*
* @example
* // p means probability of this variant, r is for range of values generated
* const probabilities = [ {p: 0.8, r: [1,5]}, {p: 0.2, r: [20,25]} ];
* // v => v|0 is a filter for each generated value, example one is equal to Math.floor(v)
* const weightGenerator = new BiasedRandom(probabilities, v => v|0);
*
* const weight = weightGenerator.generate();
* // With a 80% probability weight will be between 1 and 5
* // With a 20% probability weight will be between 20 and 25
*
* @param {Object[]} probabilities
* @param filter
*/
constructor (probabilities, filter = false) {
this.probs = probabilities.sort((c, n) => c.p > n.p);
this.filter = filter;
if (!this._checkProbs()) {
throw new Error('Sum of probabilities cannot be more than 1');
}
this.bounds = [];
let bottomBound = 0;
for (let i = 0; i < this.probs.length; i++) {
const entry = this.probs[i];
this.bounds.push([bottomBound, bottomBound + entry.p]);
bottomBound = entry.p;
}
}
_checkProbs () {
return this.probs.reduce((acc,n)=>acc+=n.p,0) === 1;
}
/**
* Generates value
*
* @returns {*}
*/
generate () {
const r = Math.random();
for (let i = 0; i < this.probs.length; i++) {
if (r > this.bounds[i][0] && r <= this.bounds[i][1]) {
const v = boundrand(...this.probs[i].r);
return (this.filter
? this.filter(v)
: v);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment