Sorry, I'm new to JS and can't seem to figure this out: how would I do probability?
I have absolutely no idea, but I'd like to do something: out of 100% chance, maybe 0.7% chance to execute function e();
and 30% chance to execute function d();
and so on - they will add up to 100% exactly with a different function for each, but I haven't figured out exactly how to do this in any form.
What I found is mostly strange high school math tutorials "powered by" Javascriptkit or something.
var decide = function(){
var num = parseInt(Math.random() * 10) + 1; // assigns num randomly (1-10)
num > 7 ? d() : e(); // if num > 7 call d(), else call e()
};
Something like this should help:
var threshhold1 = 30.5;
var threshhold2 = 70.5;
var randomNumber = random() * 100;
if (randomNumber < threshhold1) {
func1()
}
else if (randomNumber < threshhold2) {
func2()
}
else {
func3()
}
This will execute func1()
with 30.5% probability, func2()
with 40%, and func3()
with 29.5%.
You could probably do it more elegantly using a dictionary of threshholds to function pointers, and a loop that finds the first dictionary entry with a threshhold greater than randomNumber
.
For instance we define a number of functions
function a () { return 0; }
function b () { return 1; }
function c () { return 2; }
var probas = [ 20, 70, 10 ]; // 20%, 70% and 10%
var funcs = [ a, b, c ]; // the functions array
That generic function works for any number of functions, it executes it and return the result:
function randexec()
{
var ar = [];
var i,sum = 0;
// that following initialization loop could be done only once above that
// randexec() function, we let it here for clarity
for (i=0 ; i<probas.length-1 ; i++) // notice the '-1'
{
sum += (probas[i] / 100.0);
ar[i] = sum;
}
// Then we get a random number and finds where it sits inside the probabilities
// defined earlier
var r = Math.random(); // returns [0,1]
for (i=0 ; i<ar.length && r>=ar[i] ; i++) ;
// Finally execute the function and return its result
return (funcs[i])();
}
For instance, let's try with our 3 functions, 100000 tries:
var count = [ 0, 0, 0 ];
for (var i=0 ; i<100000 ; i++)
{
count[randexec()]++;
}
var s = '';
var f = [ "a", "b", "c" ];
for (var i=0 ; i<3 ; i++)
s += (s ? ', ':'') + f[i] + ' = ' + count[i];
alert(s);
The result on my Firefox
a = 20039, b = 70055, c = 9906
So a run about 20%, b ~ 70% and c ~ 10%.
Edit following comments.
If your browser has a cough with return (funcs[i])();
, just replace the funcs array
var funcs = [ a, b, c ]; // the old functions array
with this new one (strings)
var funcs = [ "a", "b", "c" ]; // the new functions array
then replace the final line of the function randexec()
return (funcs[i])(); // old
with that new one
return eval(funcs[i]+'()');
// generate cumulative distribution function from weights
function cdf(weights) {
// calculate total
var total = 0;
for(var i=0; i<weights.length; i++) {
total += weights[i];
}
// generate CDF, normalizing with total
var cumul = [];
cumul[0] = weights[0]/total;
for(var i=1; i<weights.length; i++) {
cumul[i] = cumul[i-1] + (weights[i]/total);
}
return cumul;
}
// pick the index using the random value
function selectInd(cumul,rand) {
for(var i=0; (i < cumul.length) && (rand > cumul[i]); ++i) {};
return i;
}
Code block to use the above
// setup (do this once)
var weights = [70,20,10];
var cumul = cdf(weights)
// get the index and pick the function
var ran = Math.random(); // 0 : 1
var func = funcs[selectInd(cumul,ran)];
// call the function
var someArgVal = 5;
var myResult = func(someArgVal);
// do it in one line
var myResult = (funcs[selectInd(cumul,Math.random())])(someArgVal);
Simplify calling code with a reusable object
function CumulDistributor(cumul,funcs) {
var funcArr = funcs;
var cumulArr = cumul;
function execRandomFunc(someArg) {
var func = funcArr[selectInd(cumulArr,Math.random())];
return func(someArg);
}
}
// example usage
var cdistor = new CumulDistributor(cumul,funcs);
var myResult = cdistor.execRandomFunc(someArgValue);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With