|
Some of the articles and demonstrations found on this site require the generation of random numbers and random number sequences. Most programming languages provide a function that returns a pseudo random number as a real value between zero and one. Well not quite - most never return one as a random value.
Sometimes you want to be able to reproduce a sequence of random numbers. Most random number functions will always return the same initial value the first time they are called and will use the previously returned value as the “seed” for the next value. This generates a reproducable sequence of random numbers. You can test this in Visual Basic by passing a negative argument to the Randomize statement to re-start the randon sequence at the same place.
You can effectively randomize the start of a random number sequence by seeding the random number generator with any arbitrary value - the system timer is a popular choice. Calling the equivalent of the Visual Basic Randomize statement before calling for a sequence of random numbers should ensure that your random number sequences are just about unique.
While the random number function only returns a value between zero and one you often want to generate random numbers with a greater range.
A Selected Range of Random Integers
The generation of random integer values with a specified range is very straightforward. The visual Basic code is shown below and it is simple enought to treat as pseudo-code and should be accessible to all.
Private Function RandomInteger(HighValue as Long, LowValue as Long) as Long RandomInteger = Int((HighValue - Lowvalue + 1) * Rnd + Lowvalue) End Function (Rnd is the VB random number generating function and Int() truncates a real number to it’s integer part)
This function works for ranges of integers that are negative, positive or that range from a negative to a positive integer.
A Selected Range of Random Real Numbers
The same technique can be applied to the generation of random real numbers in a specified range but again we have to deal with the fact that the Visual Basic Rnd function never returns one as a value.
Private Function RandomReal(HighValue as Double, LowValue as Double) as Double Dim RetVal as Double
RetVal = HighVal + 0.1 Do Until RetVal >= LowVal and RetVal <= HighVal RetVal = (HighValue - LowValue + 1) * Rnd + LowValue Loop RandomReal = RetVal End Function
In, test this function produced an even distribution of real numbers in the specified range with the high and low values turning up in the sequences when the sample size was large enough to make this probable.
Biased Random Number Sequences
While admiting that the title above may be oxymoronic one often needs to generate one or more “different” numbers with a higher (or lower) chance of certain values or ranges coming up. The MENACE noughts and crosses machine used feedback to alter the likelyhood of a given move being repeated in a given situation. The software simulation needed to allow an opportunity for any of the available moves to be made but biasing the response towards the moves with the highest weightings.
Selecing a weighted integer value at random
The Menace machine simulation demonstrates a simple approach that could be widened to many other applications. The Menace machine must decide where to place an X in a noughts and crosses (tic tac toe) game. The possible options are weighted by feedback during training to make it more likely that the machine will pick a move that contributes to a win and to make losing moves less likely. The simulation needed a routine that would return a value between 0 and 8 (the nine possible playing position on the board). In the code snippet below (based upon the actual simulation function) the weightings are stored in the PlayWeights array. A zero value in the PlayWeights array indicates that the move is not available. Positive values in the PlayWeights array are used to bias the returned integer value.
Private Function PickPlay(PlayWeights() as Integer) as Integer Dim RetVal as Integer, PlayLoop as Integer, TopNum as Integer, PlayNum as Integer
For PlayLoop = 0 to 8 ‘Add up all of the weights TopNum = TopNum + PlayWeights(PlayLoop) Next PlayLoop ‘Pick a random integer in the range one to that total PlayNum = Int(TopNum * Rnd + 1) TopNum = 0 For PlayLoop = 0 to 8 TopNum = TopNum + PlayWeights(PlayLoop) If PlayWeights(PlayLoop) > 0 Then ‘Count forward till the weightings equal or exceed the random value If TopNum >= PlayNum Then RetVal = PlayLoop Exit For ‘we have the biased random result so jump out of the loop End If End If Next PlayLoop PickPlay = RetVal End Function
In test, this routine returned integer values in the expected proportions as set by the weightings.
Weighting Random Real Numbers
Weighting a range of integers to influence a sequence of randomly picked values was pretty straightforward as you can see above. Managing the same trick with a sequence of real numbers is a little more problematic. The number of real numbers between zero and one is infinite. While the binary coding of real numbers within our software systems limits the number of possible numbers in a given range it does little to diminish the practical barriers to this direct approach.
Practical solutions would need to be based upon weighted ranges of values.
Gaussian Random Values
On occasion one wants to weight random values so that (when plotted) they would form a bell curve. Some sequences of numbers do this naturally. If you plot the sum of six dice over a good number of “throws” then the incidence of the sums (from 6 to 36) will follow a bell curve. This is known as a Gaussian distribution. The picture below shows a plot of just such a sequence of six dice combinations.
The development of Artificial Neural Networks using Evolutionary Algorithms often requires the ability to apply mutations to values that are normally very small but on occasion can be large. The mutations therefore can be supplied by a suitable gaussian distribution of random values. A set of such values will have a mean of zero and a negative and positive distribution around zero that fits into a natural bell curve.
The Visual Basic code below will supply a range of random values that form a Gaussian distribution. The code is simple to follow and should allow anyone to develop their own Gausian random number generating function in any programming language.
Private Function GetGausse() As Double 'This Function returns a standard Gaussian random number 'based upon the polar form of the Box-Muller transform Dim Work1 As Double, Work2 As Double, Work3 As Double Const Two = 2#, One = 1# Work3 = Two Do Until Work3 < One Work1 = Two * Rnd - One Work2 = Two * Rnd - One Work3 = Work1 * Work1 + Work2 * Work2 Loop Work3 = Sqr((-(Two) * Log(Work3)) / Work3) GetGausse = Work1 * Work3 'a second valid value could be returned by Work2 * Work3 End Function Notes: Visual Basic Doubles are double precision floating point numbers (single precision would work just fine). The Sqr() function returns a square root and the log() function returns a logarithm to base e. The constants are floating point representations of 2 and 1 but do not need to be declared as constants - they could be represented by the actaul values in the code.
In test, this function supplied a nicely formed Gaussion distribution of values from aproximately -5 to + 5.
Gaussian random values within a set range
You might want to restrict or extend the range of your Gaussian random values. The following Visual Basic code snippet makes a practical job of this. Although it is certainly mathematically imperfect it has proven fit for purpose.
The function calls the GetGausse() function described above and clearly the two could be amalgamated into a single function in many applications.
Private Function GausseInRange(PlusorMinus as Double) as Double GausseInRange = (PlusorMinus / 5) * GetGausse End function
This provides sattisfactory results for limiting value ranges less than plus or minus one (+1 to - 1) as well as for larger value real number ranges.
Are My Random Numbers Random? (or you surely test the stuff you use?)
How do we know that our random number sequences have the right characteristics? I usually find that code and algorithms downloaded from the Internet contain minor errors and sometimes do not deliver what they are supposed to deliver. I certainly came across random number functions that failed relatively simple tests of fitness.
I wrote a simple program to generate many thousands of numbers using a range of random number processing functions (including those above). I then checked the mean, standard deviation, maximum and minimum values and plotted the incidence of specific values or ranges on a graph to check the distribution visually. I was then able to sattisfy myself which performed as intended and which failed to deliver the goods.
Yes, I tested the Visual Basic Rnd function itself. This produced very sattisfactory results with a sample size in excess of 100,000 - a nice even distribution with acceptable values for the mean and standard deviation. Certainly good enough for my normal purposes although something a little more rigerous is a must for (say) cryptography.
Why Pseudo Random?
Why do we call the numbers generated by our programming languages pseudo-random numbers? Simple - it is because they are not true random numbers. True random numbers are generated by random events. You could sit and throw one or more dice to generate your own or take advantage of variations in solar radiation - use anything to generate your numbers where the last value can’t influence the next. Alternately you use a computational proces to generate numbers that have a random distribution but we have to call these pseudo random numbers.
To get your hands on some true random numbers and to learn more about them visit www.random.org - an interesting web site.
|