Creating pseudo random numbers

On a recent project I needed to create graphical patterns that looked random but in fact had to be deterministic based on a few seed numbers. As an example think about drawing a bunch of circles that appear to be drawn in random positions and with random sizes. If the seed numbers are the same the patterns will be exactly the same. But change the seed numbers by just one digit and the pattern will look completely different. Another example is the BitmapData.perlinNoise() method. Apply the method with the same seed number and you get exactly same distribution of noise.

I created this PseudoRnd class to help with this process. Just create an instance of the class and then ask for the nextRnd and it will return a number that seems to be random.

Example
var pseudoRnd_a:PseudoRnd = new PseudoRnd( 1234 );
var myFirstRndNumber:Number = pseudoRnd_a.nextRnd(); // 0.5671267126712671

var pseudoRnd_b:PseudoRnd = new PseudoRnd( 1234 );
var mySecondRndNumber:Number = pseudoRnd_b.nextRnd(); // 0.5671267126712671

var pseudoRnd_different:PseudoRnd = new PseudoRnd( 1235 );
var myDifferentRndNumber:Number = pseudoRnd_different.nextRnd(); // 0.8148613824861383

Notice that the first two instances create exactly the same pseudo random number because they have the same seed. Those two instances will continue to create the same sequence of numbers forever. The third instance – pseudoRnd_different – produces a different number and always will.

In the Explorer below you can see it running. Every second it generates another set of 1,000 random numbers and the top bar chart displays the distribution to show how random it is. The bottom bar chart displays the cumulative results and you can see that over time the distribution evens out. So it seems pretty random to me.

view source

I ran some speed comparisons with the Math.random() method and was pleased that the PseudoRandom class is only about 1,000 times slower. I don’t think that’s too bad considering that Math.random() is very low level.

Here’s the gist of how the PseudoRnd class opperates when calling the get nextRnd method.

  • Take a combination of the seed and the number of times the method has been called – rndCount – along with the sum of all the numbers created at this point – _sumRndNumbers – and create a really nasty number using some combination of Math.sin() and Math.sqrt() calls. Suppose that creates the number 0.18948219585210393
  • Take the number from the first step and create a String
  • Take that String and create an array of characters – digitsArray-  where each element of the array is one of the characters from the previous step. Start looking at the third element which is the first character after the decimal point. The array would look like this: a[0]=1, a[1]=8, a[2]=9, a[3]=4…
  • Reverse the array
  • Now it gets a little weird

Here’s the code that runs through the digitsArray to create a pseudo random number:

// The array 'digitasArray' contains 19 characters, all numbers.
// To create a pseudo random number we look at the value of the
// number contained at digitasArray[0], which is indexSum.
// Then we use that number as an index to go and get a number
// from the digitsArray to be appended to the rndString.

// Not only does the number that we picked out of digitsArray get
// added to the rndString. It also gets added back to indexSum.
// So the next time through the loop we are looking at a different
// index of the digitsArray. You can see that a modulus of the
// digitArray.length is used so that we always stay within the range
// of the elements that digitsArray contains.

var rndString:String = '.';
var indexSum:int = digitsArray[0];
var digitsArrayLen:int = digitsArray.length;
var multiplyer:Number = 0.1;
while( rndString.length < 18 ) {
var n:Number = digitsArray[ indexSum % digitsArrayLen ];
rndString += String( n );
indexSum += n;
}

When I discovered that this method was roughly 1,000 times slower than Math.random() I tried a variation of this approach in which Strings were never used. Because I thought that it was probably the String concatenation that was slowing everything down. But no. Try as I might I couldn’t get a purly numerical approach to run nearly as fast so I went back to the String approach.

I wouldn’t recomend using this in some algorythm where you need thousands of random numbers every second. But if you just need a few here and there and most importantly if you need to be able to exactly recreate the sequence of random numbers then this might be the class for you.

Addendum
It occurs to me that I can skip the conversion to an array and just use the charAt() method on the String. I’ll modify the code soon and test to see if that improves the speed.