views:

128

answers:

5

I'd like to create a random boolean in JavaScript, but I want to take the previous value into account. If the previous value was true, I want it to be more likely for the next value to be true. At the moment I've got this (this is in the context of a closure - goUp and lastGoUp are locals to the containing scope):

function setGoUp() {
    goUp = getRandomBoolean();

    if(lastGoUp) {
        goUp = getRandomBoolean() || goUp;
    }
    else {
        goUp = getRandomBoolean() && goUp;
    }
    lastGoUp = goUp;
}

So, the algorithm goes:

  1. Get a random boolean
  2. If the random boolean from the previous call was True:

    a) get another random boolean, and or these two together

    b) else get another random boolean and and these together.

I'm sure this algorithm could be simplified. I wondered about doing:

if(lastGoUp && goUp) {
    goUp = goUp * (getRandomBoolean() || goUp);
}

but that seems really dirty.

There's also a problem with this algorithm which means that I can only double the chance of getting the same boolean again - I can't tweak it easily. Any ideas?

A: 

I would just make the probability of getting value true be an explicit float variable p. Then I could tweak it easily, by increasing p in some way if I got true last time or by doing nothing with it if I got 'false'.

kohomologie
+6  A: 

You should define the distribution you want, but maybe you are looking for the following?

if (lastGoUp) {
    goUp = getRandomFloatBetween0And1() < 0.8;
} else {
    goUp = getRandomFloatBetween0And1() < 0.2;
}
meriton
Of course! I didn't start off with any kind of bias, so I was trying to work out how to bias a pre-existing boolean. Thanks :)
Skilldrick
Btw, I decided to go with `< 0.8` and `> 0.8` because that made more sense to me. It was also clearer to make 0.8 into a named constant.
Skilldrick
+3  A: 

Instead of getting a random boolean, get a random number, say between 0 and 99. Keep a threshold value instead of the last number, and adjust the threshold according to the result:

var threshold = 50;

function setGoUp() {
   goUp = getRandomNumber() < threshold;
   threshold += goUp ? -10 : 10;
}

This would keep a running tab, so if you get consecutive results that are the same, the probability would keep falling for that result.

If you only want to consider the last result, you would instead set the threshold to a specific value:

threshold = goUp ? 40 : 60;
Guffa
Thanks. I'll definitely bear this in mind if I need to take more than one result into account.
Skilldrick
A: 

Can replace Math.random for a better randomizer.

var setGoUp = (function(){
   var last;
   return function(){
       // if last 66% chance for true else 50% chance of true.
       return !!(last ? Math.random()*3 : Math.random()*2);
   }
}());

!! converts anything to a boolean, 0 = false.

BGerrissen
+1  A: 

If you only want the probability of the next event to depend on the current value, and not the history of values up til now, what you want is called a Markov process. Often these are implemented with a 2D table of probabilities that you look up (prob of each next outcome given current one), but for a simple bool-valued event, an if statement is sufficient (see meriton's answer; note that it corresponds to a table of probabilities [0.8 0.2; 0.2 0.8]).

If you want something that gets more likely, say, the more successes you get in a row, then you need to devise a sequence of probabilities for success that perhaps approaches, but does not exceed, 1. There are any number of formulas which can do this, depending on how strong you want the bias to become and how quickly you want it to get there.

Owen S.
The old solution did work, because I was generating two random booleans each time. If `lastGoUp` was `true` then I `or`d the two booleans together (1 in 4 chance of also being true), and if `lastGoUp` was `false` I `and`ed the two booleans together (1 in 4 chance of also being false). It was a pretty messy algorithm though.
Skilldrick
Ah, I see, you're right - so that's in effect doing something like [.75 .25; .25 .75]. I deleted my assertion that that wouldn't work.
Owen S.
No problem. Like I said, it wasn't the cleanest code!
Skilldrick