PDA

Click to See Complete Forum and Search --> : Tutorial - Random Numbers [VB6 and earlier]


manavo11
Mar 3rd, 2004, 09:40 AM
Many questions in VB are regarding random numbers. In this tutorial I will try and explain the basic ideas regarding random numbers so it'll be easier for you to create your applications.

Intro - The Rnd Function

The first thing you need to know is the function that generates a random number. The function is called : Rnd. Here is how you use it :

1) Open a new project in VB.
2) In the load event of your form add the following code :

Private Sub Form_Load()
Dim i As Integer
For i = 1 To 10
Debug.Print Rnd
Next
End Sub

3) Run the project. In the Immediate window you will notice that 10 numbers have been printed.

manavo11
Mar 3rd, 2004, 09:41 AM
Truly Randomizing - The Randomize Statement

After you run the program once you have the values in the Immediate window. Run the program again and compare the first 10 numbers with the last 10 numbers. Notice a similarity? The Rnd function has a predetermined set of numbers that it shows every time call the rnd function. So every time you start your app, it starts from the beginning showing the same numbers again. How do you avoid this? The Randomize statement makes the Rnd function generate truly random numbers.

TIP : Don't keep using the randomize statement because then it loses it's meaning... Use it only once, right before you start creating random numbers the first time.

TIP : You also have the optional number after in the randomize statement. That number will cause the numbers to be generated randomly but based on that number. So Randomize 2 will always return the same numbers. This can be used in encryption algorithms ;)

Comment from VB help :

Randomize uses number to initialize the Rnd function's random-number generator, giving it a new seed value. If you omit number, the value returned by the system timer is used as the new seed value.

If Randomize is not used, the Rnd function (with no arguments) uses the same number as a seed the first time it is called, and thereafter uses the last generated number as a seed value.

Note : To repeat sequences of random numbers, call Rnd with a negative argument immediately before using Randomize with a numeric argument. Using Randomize with the same value for number does not repeat the previous sequence.


Private Sub Form_Load()
Randomize
Dim i As Integer
For i = 1 To 10
Debug.Print Rnd
Next
End Sub

Now that we added the Randomize statement you can see that every time you run the application, different numbers are produced. If on the other hand you do this :

Private Sub Form_Load()
Randomize 8
Dim i As Integer
For i = 1 To 10
Debug.Print Rnd
Next
End Sub

you'll notice that the same numbers are generated (the encryption I was saying)...

manavo11
Mar 3rd, 2004, 09:42 AM
The million dollar question...

... or the most commonly asked question is : "How can I generate a number between 2 other numbers?"
The main problem with this is that many people haven't realised that the Rnd function returns a value less than 1 BUT greater than or equal to zero (0<=Rnd<1). So since most people think that the Rnd function can generate the number 1, the algorithms they use are incorrect. The correct way is this :

Int((upperbound - lowerbound + 1) * Rnd + lowerbound)

Which can easily be put into a function :

Private Function RandomInteger(Lowerbound As Integer, Upperbound As Integer) As Integer
RandomInteger = Int((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

and an example of using it is :

Private Function RandomInteger(Lowerbound As Integer, Upperbound As Integer) As Integer
RandomInteger = Int((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

Private Sub Form_Load()
Randomize 'Just once to start getting random numbers
MsgBox RandomInteger(1, 52)
End Sub

The code above would be used most of the times for a card game, to draw a card at random. If we set Lowerbound=1 and Upperbound=6 then we would have ourselves dice rolling code :)

manavo11
Mar 3rd, 2004, 09:44 AM
Series Of Unique Random Numbers

The next most popular question is "How to create unique series of random numbers (doesn't have duplicates). Usually this is used for card games or dice rolling games. There are two ways of doing it. In theory both will work, but there is a major advantage of one way as you will see soon ;)

1st option (most common) :
Follow these steps :
1) Generate a random number
2) Store it in an array
3) Generate another random number
4) Compare it with the other elements of the array
5) If it exists then generate another random number and goto step 4, if it doesn't exist add it to the array
6) Repeat as many times as needed steps 3-5

An example code would be this :

Option Explicit 'Force variable declaration

Private Sub Form_Load()
Dim Ar(1 To 100) As Integer 'The array to store it in
Dim i, j As Integer 'Counters for loops
Dim X As Integer 'Variable to store the random generated number
Dim bFound As Boolean 'Boolean to check if the value has been generated before

Randomize 'Just once to ensure that we get random values

For i = 1 To 100
Do 'Start the loop that generates a random number and checks if it has already been generated
X = RandomInteger(1, 100) 'Generate a random number
bFound = False 'Set the boolean to false, if we find the number while searching the array, we'll set it to true which means that we already have that number
For j = 1 To i 'We only need to check up to i (since we haven't put any values in the rest of the array)
If Ar(j) = X Then 'If an item of the arrray is the same as the last generated number
bFound = True 'Set the boolean to true (it already exists)
DoEvents 'To not freeze until the looping is done
Exit For 'Since we found it there is no need to check the rest
End If
Next
Loop Until bFound = False 'If it wasn't found then we'll add it, if it was found then we go back to generating a new number and comparing it with all the items of the array
Ar(i) = X 'Add it to the array
Next

ShowInTextBox Text1, Ar 'Just to print the data and see it
End Sub

Private Function RandomInteger(Lowerbound As Integer, Upperbound As Integer) As Integer 'The random number generator code
RandomInteger = Int((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

Private Sub ShowInTextBox(TB As TextBox, A() As Integer) 'Just a sub to show the data in a textbox
Dim i As Integer

TB.Text = ""

For i = 1 To UBound(A)
TB.Text = TB.Text & CStr(A(i)) & vbCrLf
Next

TB.Text = Left$(TB.Text, Len(TB.Text) - 2)
End Sub


Unfortunatelly, there is a serious drawback with this method. It all seems fine, but since you are generating a small amount of random numbers then you'll be OK. But if you are trying to generate a large amount of random numbers then theoretically some number might never be generated or at least it could take a while for the number to be generated. This could clearly create an unwanted delay in your program.
I know, the chance is very very small but it will at least delay the process which could cause problems. So here is another option :

2nd option (better) :
You do follow these steps :
1) You create all the numbers you need and store them in a collection
2) Generate a random number
3) Get the element of the collection that has the index of the randomly generated number (Here is the main advantage. You will always get an element since you are generating a number that will always be the index for an element of the array. Since you remove it later, you don't need the time consuming checking ;) )
4) Add that number to the random number array that you want
5) Remove that number from the collection with the list of numbers
6) Repeat 2-5 until the array with the list of numbers is empty

An example code would be this :

Option Explicit 'Force variable declaration

Private Sub Form_Load()
Dim Col As Collection 'The collection we will use to store the numbers
Dim Ar(1 To 100) As Integer 'The array to store the values from the collection
Dim i As Integer 'Counter for loops
Dim X As Integer 'Variable to store the random generated number

Randomize 'Just once to ensure that we get random values

Set Col = New Collection 'Get the collection ready to use

For i = 1 To 100 'The possible numbers that we can have as a result is all the numbers from 1 to 100 so
Col.Add i 'add all the possible numbers to the collection
Next

For i = 1 To 100 'Now to get the 100 numbers we added in the previous loop
X = RandomInteger(1, Col.Count) 'Get a random item from the collection (that exists for sure)
Ar(i) = Col.Item(X) 'Add it to the array
Col.Remove X 'Remove it so we don't add it again
Next

ShowInTextBox Text1, Ar 'Just to print the data and see it
End Sub

Private Function RandomInteger(Lowerbound As Integer, Upperbound As Integer) As Integer 'The random number generator code
RandomInteger = Int((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

Private Sub ShowInTextBox(TB As TextBox, A() As Integer) 'Just a sub to show the data in a textbox
Dim i As Integer

TB.Text = ""

For i = 1 To UBound(A)
TB.Text = TB.Text & CStr(A(i)) & vbCrLf
Next

TB.Text = Left$(TB.Text, Len(TB.Text) - 2)
End Sub

manavo11
Mar 3rd, 2004, 09:45 AM
Proof

Now, with the above example it is hard to realise that the second option is better and faster since it's just 100 numbers. In the first case (array) it takes an average of 31-47 milliseconds to complete the task. In the second case it takes 0 milliseconds to complete the task.
So to explain myself better, here is an example with 10000 numbers and a way to track how long was needed to create the list completely :

Array code :

Option Explicit 'Force variable declaration

Private Declare Function GetTickCount Lib "kernel32" () As Long 'The GetTickCount
'function retrieves
'the number of
'milliseconds that
'have elapsed since
'Windows was started.

Private Sub Form_Load()
Dim Ar(1 To 10000) As Integer 'The array to store it in
Dim i, j As Integer 'Counters for loops
Dim X As Integer 'Variable to store the random generated number
Dim bFound As Boolean 'Boolean to check if the value has been generated before
Dim S As Long 'Variable to store the number of milliseconds that have elapsed since
'Windows was started when we begin the task

Randomize 'Just once to ensure that we get random values

S = GetTickCount 'Store the number of milliseconds that have elapsed since Windows was started when we begin the task

For i = 1 To 10000
Do 'Start the loop that generates a random number and checks if it has already been generated
X = RandomInteger(1, 10000) 'Generate a random number
bFound = False 'Set the boolean to false, if we find the number while searching the array, we'll set it to true which means that we already have that number
For j = 1 To i 'We only need to check up to i (since we haven't put any values in the rest of the array)
If Ar(j) = X Then 'If an item of the arrray is the same as the last generated number
bFound = True 'Set the boolean to true (it already exists)
DoEvents 'To not freeze until the looping is done
Exit For 'Since we found it there is no need to check the rest
End If
Next
Loop Until bFound = False 'If it wasn't found then we'll add it, if it was found then we go back to generating a new number and comparing it with all the items of the array
Ar(i) = X 'Add it to the array
Next

'At the end we will subtract the number of milliseconds that had elapsed
'when the task started from the number of milliseconds that have elapsed
'when the task is complete and show it in the form's caption
Me.Caption = GetTickCount - S

ShowInTextBox Text1, Ar 'Just to print the data and see it
End Sub

Private Function RandomInteger(Lowerbound As Integer, Upperbound As Integer) As Integer 'The random number generator code
RandomInteger = Int((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

Private Sub ShowInTextBox(TB As TextBox, A() As Integer) 'Just a sub to show the data in a textbox
Dim i As Integer

TB.Text = ""

For i = 1 To UBound(A)
TB.Text = TB.Text & CStr(A(i)) & vbCrLf
DoEvents
Next

TB.Text = Left$(TB.Text, Len(TB.Text) - 2)
End Sub

And the collection code :

Option Explicit 'Force variable declaration

Private Declare Function GetTickCount Lib "kernel32" () As Long 'The GetTickCount
'function retrieves
'the number of
'milliseconds that
'have elapsed since
'Windows was started.

Private Sub Form_Load()
Dim Col As Collection 'The collection we will use to store the numbers
Dim Ar(1 To 10000) As Integer 'The array to store the values from the collection
Dim i As Integer 'Counter for loops
Dim X As Integer 'Variable to store the random generated number
Dim S As Long 'Variable to store the number of milliseconds that have elapsed since
'Windows was started when we begin the task

Randomize 'Just once to ensure that we get random values

Set Col = New Collection 'Get the collection ready to use

S = GetTickCount 'Store the number of milliseconds that have elapsed since Windows was started when we begin the task

For i = 1 To 10000 'The possible numbers that we can have as a result is all the numbers from 1 to 100 so
Col.Add i 'add all the possible numbers to the collection
Next

For i = 1 To 10000 'Now to get the 100 numbers we added in the previous loop
X = RandomInteger(1, Col.Count) 'Get a random item from the collection (that exists for sure)
Ar(i) = Col.Item(X) 'Add it to the array
Col.Remove X 'Remove it so we don't add it again
Next

'At the end we will subtract the number of milliseconds that had elapsed
'when the task started from the number of milliseconds that have elapsed
'when the task is complete and show it in the form's caption
Me.Caption = GetTickCount - S

ShowInTextBox Text1, Ar 'Just to print the data and see it
End Sub

Private Function RandomInteger(Lowerbound As Integer, Upperbound As Integer) As Integer 'The random number generator code
RandomInteger = Int((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

Private Sub ShowInTextBox(TB As TextBox, A() As Integer) 'Just a sub to show the data in a textbox
Dim i As Integer

TB.Text = ""

For i = 1 To UBound(A)
TB.Text = TB.Text & CStr(A(i)) & vbCrLf
DoEvents
Next

TB.Text = Left$(TB.Text, Len(TB.Text) - 2)
End Sub

On my PC, the array code needed 116328 milliseconds which means about 116 seconds which is almost 2 minutes!
The collection code needed 13219 milliseconds which is about 13 seconds!

manavo11
Mar 3rd, 2004, 09:47 AM
The End

Well, that's all folks! :D
This is the end of this tutorial about random numbers. I hope you found it useful and helpful so your programming days from now on will be easier. :afrog:

If you have any questions regarding this tutorial, don't be shy, drop me an e-mail and I'll gladly help you.

Thanks,
manavo

si_the_geek
Mar 3rd, 2004, 12:36 PM
The code/files within this thread (submitted: 03-03-2004) have been checked for malware by a moderator.

Disclaimer: This does not necessarily mean that any compiled files (DLL/EXE/OCX etc) are completely safe, but any supplied code does not contain any obvious malware. It also does not imply that code is error free, or that it performs exactly as described.

It is recommended that you manually check any code before running it, and/or use an automated tool such as Source Search by Minnow (available here (http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=22222&lngWId=1) or here (http://sourcesearch2.homestead.com/)).
If you find any serious issues (ie: the code causes damage or some sort), please contact a moderator of this forum.

Usage of any code/software posted on this forum is at your own risk.

Vatyk
Sep 21st, 2007, 10:13 PM
Hi all,

I am new, to this forum and also to VB.Net and I encountered a problem. I need an array that contains 100 random numbers, between 1 and 100. More specifically, the array must contain all the numbers between 1 and 100, but in random order, and I don't know how to do that. Any help would be appreciated.

Thank you.

si_the_geek
Sep 22nd, 2007, 01:36 PM
Welcome to VBForums :wave:

This tutorial is actually for Classic VB, not VB.Net.

You should ask in our VB.Net forum (http://www.vbforums.com/forumdisplay.php?f=25), as the methods are different.

Vatyk
Sep 22nd, 2007, 06:50 PM
Thank you,

I will post it on the VB.Net forum, as you suggested.

NARL
Nov 24th, 2008, 01:48 AM
Pls Anyone Help Me Here, I Dont Get The Resultz On The Explanation Above

http://i37.tinypic.com/2cpuvsi.jpg

si_the_geek
Nov 24th, 2008, 06:55 AM
Welcome to VBForums :wave:

As the code uses Debug.Print, the numbers will be printed to the Immediate window - if it isn't visible, select it on the View menu.

Stevenson00719
Jan 12th, 2010, 05:08 AM
Your Random Number tutorial is extremly helpful so firstly id like to thank you for posting it.

Would it be possible to change the above code (1st option) so that you could call a list of random numbers one at a time using a command button?

Thanks again

Robert Stevenson

PVB_Great
Feb 17th, 2010, 09:40 AM
Hi,

This is really very useful for the new vb programmers.

ruipedromachado
Jun 8th, 2010, 05:02 PM
Dim randomnumber As New Random
MessageBox.Show(randomnumber.Next())

only number between 1 and 9

Dim randomnumber As New Random
MessageBox.Show(randomnumber.Next(1,9))

TheBigB
Jun 8th, 2010, 06:54 PM
I don't think that is VB6.
Visual Basic.NET and Classic Visual Basic are separated on this forum.
Take a look at the forum index (http://www.vbforums.com/index.php) and learn about all the different categories.

Nightwalker83
Jun 9th, 2010, 02:11 AM
I don't think that is VB6.
Visual Basic.NET and Classic Visual Basic are separated on this forum.
Take a look at the forum index (http://www.vbforums.com/index.php) and learn about all the different categories.

It's not it's vb.net! ruipedromachado should have said so in his post. Although, seeing as there is no specification in the original post or the thread title regarding which Visual Basic version is being talked about I can see why he got confused.

si_the_geek
Jun 9th, 2010, 05:24 AM
I've added VB6 to the thread title to save that kind of confusion in future.

joaquim
Nov 1st, 2010, 11:44 AM
how is these possible?
the pc can random, always, the same number... in diferent executions... can anyone explain to me why?

si_the_geek
Nov 1st, 2010, 12:19 PM
You need to use the Randomize statement as shown in post #2.

If you want different numbers each time, call Randomize just once at the start of your program (eg: in Form_Load).

If you want to be able to repeat the same set of numbers, call Rnd with a negative argument first, and then Randomize with whatever number you want, eg:
Rnd -1
Randomize 2345