Random numbers and drawing lots with Excel VBA
A reader asked me if I would make an example on how to generate random numbers with Excel VBA, and I did because it was funny.
Random numbers can be used for spot checking, encryption, drawing lots etc., and it is a science by itself.
With the worksheet function "= RAND()" you can get a random number in a cell, and in VBA you use the function "Rnd()".
Returning to the reader's request he wanted seven random and different "winner numbers" from a table. This implicates that if the same number occurs in the table more than once, the propability for drawing that number increases.
In other words: He wanted to cheat!
Below I show how to do that (the procedure LottoCheat). Afterwards I show, how VBA can make a table with unique random numbers (no duplicates), so you can have a fair draw.
The example also shows how you can define an interval for the random number (e.g. 1 - 1000).
Pseudorandom numbers
However before I proceed with the examples, I must say, that Excel doesn't generate true random numbers like e.g. throwing a dice - it generates socalled pseudorandom numbers.
VBA (and other programs) uses an algorithm that uses a "seed value" as start value. Programs will often use the computers clock to generate this seed value.
If you know the value, it is theoretically possible to calculate the "random" numbers, and that would be unfortunate if they are used for e.g. encryption or lotto!
The command "Randomize" forces VBA to reset the number generator so it gets a new seed value.
It is all pretty complicated, but at Wikipedia you can read more about pseudorandom numbers.
Drawing lots
Below is an example for drawing lots from a table. For the example to work there must be a table starting in cell A1 on the first worksheet. To test the macro, highlight it with the mouse, copy (CTRL+C) and paste (CTRL+V) into a VBA module.
Sub LottoCheat()
Dim lVal As Long
Dim rInput As Range
Dim rCell As Range
Dim colCheck As Collection
Dim colWinners As Collection
On Error GoTo ErrorHandle
Set rInput = Worksheets(1).Range("A1").CurrentRegion
If rInput.Count < 8 Then
MsgBox "There are too few cells in the table.", vbCritical
GoTo BeforeExit
End If
For Each rCell In rInput
If IsNumeric(rCell.Value) = False Or Len(rCell.Value) = 0 Then
MsgBox "The cells must be numbers.", vbCritical
GoTo BeforeExit
End If
Next
On Error Resume Next
Set colCheck = New Collection
For Each rCell In rInput
With rCell
colCheck.Add Int(.Value), Str$(Int(.Value))
End With
If colCheck.Count = 8 Then Exit For
Next
If colCheck.Count < 8 Then
MsgBox "There must be at least 8 different values in the table."
GoTo BeforeExit
End If
Set colWinners = New Collection
Randomize
For Each rCell In rInput
With rInput
lVal = Int(.Count * Rnd() + 1)
colWinners.Add Int(.Item(lVal).Value), _
Str$(Int(.Item(lVal).Value))
If colWinners.Count = 7 Then Exit For
End With
Next
On Error GoTo ErrorHandle
Set rCell = Worksheets(2).Range("A1")
rCell.Value = "Winning lots:"
With colWinners
For lVal = 1 To .Count
rCell.Offset(lVal, 0).Value = .Item(lVal)
Next
End With
Worksheets(2).Activate
BeforeExit:
Set rCell = Nothing
Set rInput = Nothing
Set colCheck = Nothing
Set colWinners = Nothing
Exit Sub
ErrorHandle:
MsgBox Err.Description & " Procedure LottoCheat."
Resume BeforeExit
End Sub
Table with unique random numbers
The example below shows how to make a table with unique random numbers - that is: without duplicates.
If you use this procedure, you can make a fair draw with the procedure above (and then you should probably not call it "LottoCheat"!).
Again: You can highlight the code with the mouse, copy (CTRL+C) and paste (CTRL+V) into a VBA module.
Sub MakeUniqueTable()
Dim rTable As Range
Dim rCell As Range
Dim lMin As Long
Dim lMax As Long
Dim lVal As Long
Dim colValues As Collection
On Error GoTo ErrorHandle
Set rTable = Worksheets(1).Range("A1", "J30")
lMin = 1
lMax = 1000
If lMax - lMin < rTable.Count Then
MsgBox "The interval is too small.", vbCritical
GoTo BeforeExit
End If
Randomize
Set colValues = New Collection
On Error Resume Next
Do Until colValues.Count = rTable.Count
lVal = Int((lMax - lMin + 1) * Rnd() + lMin)
colValues.Add lVal, Str$(lVal)
Loop
On Error GoTo ErrorHandle
With colValues
For lVal = 1 To .Count
rTable.Item(lVal).Value = .Item(lVal)
Next
End With
BeforeExit:
Set rCell = Nothing
Set rTable = Nothing
Set colValues = Nothing
Exit Sub
ErrorHandle:
MsgBox Err.Description & " Procedure MakeUniqueTable."
Resume BeforeExit
End Sub
As a final note I'll add, that the function Rnd() happily returns numbers with decimals. That is why I have converted the numbers to Integers using the VBA function Int().
Related:
|