Random Numbers
A question that often arises is "How do I generate a random number?". The purpose of this article is to answer that question and look into some of the background behind random numbers.
Simply put, you can get a pseudorandom number by using the Rnd() function. This function returns a double precision number between 0 and 1, inclusive of 0 but exclusive of 1. This means that you could theoretically get a 0 from this function, but you cannot get a 1. You can get close though...like maybe 0.9999999999. You can use this function to generate a pseudorandom number in any range. For instance, suppose you wish to get a random number between 1 and 100, inclusive. You could write: i = INT(RND() * 100) + 1 To explain: a) the RND() function returns a number between 0 and 1 (exclusive of 1) b) we multiply by 100 to get a number between 0 and 100 (exclusive of 100) c) we use the INT function to truncate the decimals and get just the integer portion. This gives us a number between 0 and 99 inclusive d) We add 1 to get a number between 1 and 100 Similarily, if we wanted a number between 5 and 57, we could write: i = INT(RND() * 53) + 5 A common error is to write the function like: i = CINT(RND() * 99) + 1 The difference here is that the CINT function rounds fractions above 0.5 up instead of dropping them totally. So we still get a number between 1 and 100, but the probabilities are not equal. You are only half as likely to get a 1 or a 100 as any other number. Let's look at a simpler example. A function to get a number between 1 and 4. BAD WAY: i = CInt( Rnd() * 3) + 1 In this example, rnd() can be a number between 0 and 1 so multiplying by 3 gives us a number between 0 and 3. We then use CINT to round the number to a whole number between 0 and 3, then add 1. So what's the problem? Well, the problem is that the odds are not equal. Code:
From To Integer Range (Difference between From and To) From this table, you can see that the chance of getting a 1 or 2 is twice as great as getting a 0 or 3. GOODWAY: i = INT(Rnd() * 4) + 1 Code:
From To Integer Range (Difference between From and To) The main point is that the range is the same for all possible outcomes. Why do I call them Pseudo random numbers instead just plain random numbers anyway? The reason is that the rnd() function doesn't actually generate a "true" random number. Instead, it uses an algorithm that mixes numbers up and generates a number that appears to be "random", but in actuallity, it is one of a fixed sequence of numbers. Typically, the function starts with a "seed" number. It uses this seed to calculate a pseudorandom number . This number is then used as the next seed. The initial seed value is the SAME everytime you start your application. So if you print out 5 random numbers, then next time you run your app, you will find that the numbers you get are the same as before. To prevent this, you explicitly load a seed value with the RANDOMIZE statement. This command inputs a specified seed value, or if no value is given, it uses the current time as a seed value. This way, you get different results everytime you run the program. You could put a RANDOMIZE statement before every call to Rnd if you want, but it's not necessary and may be counter productive. Remember, if you don't specify a seed value with Randomize, Rnd will use the previous number as a seed. So you have a pseudo random number as a seed to get the next random number. Whereas if you use Randomize all the time, you are using the current time as a seed. A value that is not nearly so random and is, in fact linear in growth and has a small amount of variability. So how does the RND() function generate a pseudo random number then? There are a number of methods, but the most common is the Linear Congruential Generator. Basically, it involves multiplying your seed by a constant, adding another constant, and using the MOD operator with yet another constant. RandomNumber = (SeedValue * FactorConstant + OffsetConstant) MOD ModConstant. To get a random number between 0 and 1, the number is then divided by ModConstant. The actual values are fairly important here... First, to get a reasonable amount of resolution, ModConstant should be quite large. If, for instance, you had a ModConstant value of 4 then your random number generator would only generate 4 possible values. eg. 0, 0.25, 0.5 and 0.75 Second, your FactorConstant should be a fairly large number. When you multiply it by seed value, you should get a number several times larger than modconstant. Third, Offset constant should be less than ModConstant. Mainly because the mod operation makes larger values pointless. The main function of Offset is to prevent certain errors. For instance, suppose you had RandomNumber = SeedValue * factorConstand MOD ModConstant. If SeedValue happened to be 0, you would be locked into 0 forever. Fourth, your function should not get locked into a cycle, as above. You have to pick your values carefully but a good rule of thumb is to use Prime Numbers. That concludes this little article. I hope it helps... "I have a plan so cunning you could put a tail on it and call it a weasel!"  Edmund Blackadder 
How to generate nonrepeating random numbers
The there are 2 basic methods for creating nonrecurring random numbers.
1) Generate a random number. Check it against a list of numbers already generated. If it exists, get another one. If it does not, add it to the list. 2) Generate a list of all possible numbers,in sequence. Use the random number generator to mix them up. Both methods have their advantages and disadvantages and the method you use depends upon your situation. If you are shuffling a deck of cards, you would use the second method. Otherwise, as the number of available cards diminishes, you spend most of your time generating invalid entries. Conversely, if you were generating positions of objects in a large universe, you would use the first method since you don't arn't going to generate all possible values, just a few. Here is some code to demonstrate the two methods: Code:
Private Function CreateRandom(ByVal num As Long, ByVal min As Long, ByVal max As Long) As Variant 
Sometimes, you want to repeat a string of numbers. This can be useful for debugging code (when you want to repeat an error so you can deal with it) or for encryption (so you can decode a message using the same set of pseudorandom numbers). There are 2 basic ways to do this.
a) If you *don't* use randomize, then by default rnd() will return the same sequence of numbers everytime you RUN the program. However, you need to exit the program and rerun it to "reset" the generator. b) You can manually reset the generator by using Randomize and passing it a seed value. You then need to call rnd() an pass it a NEGATIVE argument (eg. 1). All subsequent calls to rnd() will then follow the same pattern. Code:
Sometimes, it is useful to know exactly how RND() works. I explained above that it is a linear congruent generator, but I didn't show the actual coefficients, mainly because I didn't know what they are. Now I know and I've reproduced the info here. From MSDN: Quote:

Random number Historgram plot
2 Attachment(s)
One way to show that the random number generator is reasonably random is to generate a histogram of the results.
You would first create an array of 1000 longs. Then, generate an random integer between 0 and 999, inclusive. Increment the value in the array element that corresponds to the random number generated. Repeat the random number generation & array increment for a significant number of samples  say, a million or more. Then, display the results The Pic below is an example of the random number generator in action  a 1000 element histogram of 10 million samples. On average, for these quantities, there should be a count of 10000 in each histogram 'slot' for a random sampling. See the attached zip file for an example of this that I threw together. . 
2 Attachment(s)
In the first post of this thread, BillSoo stated:
Quote:
I modified the double random function (& histogram) app I posted in the code library a few months ago by adding a checkbox, and inserting code in the dblRnd function to call RANDOMIZE if the box is checked. Below is a screen shot of two typical histograms resulting from this; the first one is the 'normal' or unmodified code, where randomize is only called once, and the second shows the effect of calling randomize with every call of rnd. As can easily be seen, calling randomize clearly adds a nonrandom element into the random number generation. A perfectly random number generation algorighm should result in a flat line; the closer to a flat line, the more random the number generation process. In the case of repititive randomize calls, the "noise" levels are much higher, indicating that these histogram boxes had many more random numbers than their neighbors. In addition, you see a sinsoidal cyclical effect in the 'random' number generation. Conclusion: As BillSoo opined, calling RANDOMIZE repetitively absolutely does result in derandomizing the distribution of numbers in the VB random number generation process. . 
This "lack of randomness" in the Randomize command occurs because in a standard random number generator there are around 2.15 bil. possible numbers. Technically, for the most part, they are "Linear Congruent Generators" (LCG's) creating a Long integer with about 2.15 bil. possible results.
The Randomize command uses the number of seconds or miliseconds, on the system clock. It almost certainly makes use of the GetTickCount API within "kernel32.dll". This returns the number of 1,000ths of a second since boot up. This sounds pretty good right? Well, it is, it's real good. But it's NOT as good as having a random number in the range of 1 to 2.15 bil.! Currently running on my machine, my GetTickCount reads "11,268,175". Now 11.3 million is not bad, but it's a FAR cry from 2.15 billion. If one considers that most computers are in use from 9am to 5pm (or there abouts) you realize that the range of possible inputs is kinda narrow... On the other hand, LCG's are designed to be VERY sensitive to their inputs. So "seeding" an LCG with 11,268,175 should have a VERY different result than 11,268,176. A 1,000th of a sec. difference can mean a LOT! Overall, I'm kinda surprised that you guys found a noticeable answer, but the reality is that if using the System Clock alone were good enough as a random number generator, they wouldn't bother creating the LCG!  Mike 
With apologies, I need to amend the above.
Loquin reminded me that BillSoo’s posting above shows that VB's random number generator only uses 24 bits and so only has about 16.8 million possible values or "states". VB is using a smaller Linear Congruent Generator ("LCG") than I had realized. When compared to the GetTickCount values I mentioned before, of around 11 million or so, these are really getting very close. The difference is in the range of possible inputs or Seeds. With the random generator, each previous number is the Seed for the next. The more random the Seed, the more random the result. And with the Seed constantly fed from itself, the results continue to have a nice random pattern. But if Randomize is called repeatedly, then you are using somewhat sequential seeds like 11,268,175 then maybe 11,268,178 (depending on how much time has passed between calls). This is not the full range of possible inputs by a long shot. Heck, with PC's today at 2,000+ mhz, it's extremely possible to repeatedly seed the same value over and over within the same milisecond! Clearly you don't want to call Randomize every time! If interested in reading about the theoretics of LCG's, one could read here http://csep1.phy.ornl.gov/rn/rn.html for a pretty good primer. It's very readable. They also get into Seeding/Randomizing routines that use the System Clock & Date in addition to the tick count. (The more variation the better...)  Mike 
There are 16777216 possible values for the random number generator. Ideally, you should go through all of these values before you start repeating numbers. Rowlek was good enough to run a test of the rnd() function and has found that, indeed, you do go through all 16777216 values before you repeat yourself.

3 Attachment(s)
One of the questions we routinely field here is “How do I calculate random numbers that are normally (Gaussian) weighted? “
First – what is meant by normal weighting? What this means is that the probability of the random numbers produced are weighted, such that the probability curve follows a bivariate normal distribution, aka, a Gaussian distribution, aka, the infamous Bell Curve. In other words, you would have a higher probability of getting a number close to the mean than you would further from the mean. Why would you want this? Well, Gaussian distribution is often useful in modeling realworld activities. For instance, if you were to take a few thousand measurements of a standard using almost any instrument, and record the results, the results data would typically follow a normal distribution. You would have a mean, and most of the data points would fall near the mean, closely grouped. The further from the mean though, the fewer the number of measurements at that point. The more accurate the instrument, the narrower this bell curve would be. Another example, in game theory, is when you fire a projectile  on average, the projectiles fall on the target. However, any given projectile may miss the average, or mean, by some distance. Again, most would be closely clustered around the bullseye, with some further and further away. The results of VB’s random number generator, on the other hand, follow what is known as a continuous uniform distribution. The probability of getting a value from the rnd function that is less than zero is zero. Likewise, the probability of getting a result from rnd that is greater than 1 is also zero. Between the upper and lower limits, the probability of getting any one value is the same as getting a different value. Now, it IS possible to transform a continuous distribution set of data into a normal distribution set. Wolfram Research (the authors of Mathematica) outline one of the common methods used – the BoxMuller Transformation. The actual algorithms, as transposed into VB code, are discussed here and here. The algorithms at the two sites are identical, however, the actual code implementation is somewhat different. (as would be expected.) I loaded the code from the Ohio State faculty site, (the first link immediately above) and made some modifications for more efficient (and more random) operation; it is attached below. The remainder of this discussion pertains to the altered function. The code posted in the GetGausse sub will work to return a random number that is weighted per gausian (normal) distribution. Like any VB random number calc, you should only issue the randomize statement once in the life of your app  normally in the form load event. Otherwise, the results may be not as random as you would think (Ref the second histogram, below, and Post #5 in this thread.) This sub assumes unity sigma, and is centered around zero. Virtually all the values returned by GetGausse will fall within +/ 5 sigma (5 to +5) although occasionally, fliers will fall outside of this range. To scale it to your purposes, multiply the result by your desired sigma, and add the desired mean. The efficiency improvements I mentioned above include that the function only needs to actually calculate the gaussian "random" numbers on every other pass. – since it is capable of calculating two, separate Gaussian random numbers on each pass, the function stores one of them internally, in a static variable, for the next time it is called. In addition, I added a scaling function (Normal) which calls the GetGausse function, in which you supply the desired sigma and mean values (they default to 1 and 0, respectively.) Code:
The images below are the typical output of a little sample app I threw together  it calls the above code 500000 times, and presents the results as a histogram. The picture box used for display is 500 pixels wide, so the mean was defined as 250 and the sigma as 50 for horizontal scaling. For our purposes, any of the 'fliers' that fall outside the pixel range of 0 to 500 are discarded. Each of the horizontal grid line represent 250 samples which fell on that xvalue. Note the nonrandom element (noise) that is evident in the righthand histgram  this was caused by calling the Randomize sub internally, within the Get_Guasse function, so that VB's internal random number generator was reseeded every time the function ran. 
Picking a random number from an arbtrary distribution
1 Attachment(s)
I have a proposed addition to the random numbers tutorial (http://www.xtremevbtalk.com/tutorscorner/76270random.html. It includes an example PDF that has (1) an infinite domain, (2) a poorly behaved inverse, (3) a CDF that (sometimes) fails a gradient search for the inverse. However, this code can be used as a baseline for implementing less complicated PDFs.
********** Begin *********** Picking a random number from an arbitrary distribution can be complicated but is necessary at times. Consider VB’s builtin random number generator. The linear congruent generator, generates uniformly distributed numbers in the range [0,1]. It has a probability distribution function that is rectangular. None of our other PDF’s of interest will have this useful shape, so what we need is a onetoone relationship between the LCG and our PDF. This relationship comes from the cumulative distribution function. The cumulative distribution tells us, for a random variable X distributed according to some PDF, the fraction of random numbers, x, that are less than or equal to X. The nice thing about linear congruent generators is that when we pick a random number, x, it is the value of the CDF at x. More bluntly, if we choose a random number in the interval [0,1], say 0.21, then the fraction of random occurrences in the distribution that are less than 0.21 is 0.21. Well, DUH! But what does that have to do with MY PDF? Our PDF has a cumulative distribution function as well (which is by definition monotonically increasing). The previous bit of fairly obvious information allows us to associate the LCG distribution with ours. If I pick a number x from distribution X and calculate the CDF of X at x and plug the result into the inverse of my CDF, I’ve effectively mapped Distribution X to my PDF. Plain and simple… The following code will produce a random number, x, picked from any CDF. All you need is the inverse! Code:
Example: I have a function that looks like: y = (x+1)*exp(a*(x+1))  exp(a*(x+1)). I want to create a PDF that is shaped like this. The first thing we have to do is normalize it such that the total area under the curve is 1 (i.e. the sum of the likelihoods of each individual event is 100%). We do this by integrating the curve over the domain. For this function, my domain of interest is [0,infinity). Integrating it over this range by parts reveals that the area is 1 / (a^2 * exp(a)). So, I divide y by this value, thereby normalizing it: Code:
y = ((x+1)*exp(a*(x+1))  exp(a*(x+1))) * (a^2 * exp(a)) Code:
CDF(z) = 1 – exp(a*z) – a*z*exp(a*z) Code:
CDFInverse(x) = (W((x1) / exp(1)) + 1) / a The following code should be able to assist you in using almost any PDF. Some PDFs (especially those with infinite domains) are not easy to implement. I gave this example just to show it's doable. In my example PDF, the parameter "a" is represented by the first parameter in the ParamArray passed to CDFInverse. Code:
You can add your own distributions to this by (1) adding a name for it into the enum and (2) creating an inverse for it. Directly invertible functions should be directly inverted. Edit: Added a histogram comparing output to the actual distribution. 
All times are GMT 6. The time now is 02:35 PM. 
Powered by vBulletin® Version 3.8.9
Copyright ©2000  2017, vBulletin Solutions, Inc.
Search Engine Optimisation provided by
DragonByte SEO v2.0.15 (Lite) 
vBulletin Mods & Addons Copyright © 2017 DragonByte Technologies Ltd.
All site content is protected by the Digital Millenium Act of 1998. Copyright©20012011 MAS Media Inc. and Extreme Visual Basic Forum. All rights reserved.
You may not copy or reproduce any portion of this site without written consent.