Why is this random number generation code not working?
I am writing a program to confirm the "Birthday Paradox".
For i = 0 To (pnum - 1)
days(i) = rnd(h:=365)
Next
It generates a random number for everyone i
(days(i))
between 1 and 365, function:
Private Function rnd(h As Integer)
Dim num As Integer
Dim rnum As Random
rnum = New Random
num = rnum.Next(1, h)
Return num
End Function
When I add a breakpoint in the for loop and look at it manually, it works fine, but if I just run the program, it puts the same random number in every interval in days (I).
Any ideas why?
Generation count works now, but the program still works differently when debugging with breakpoints.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim prc As Integer
For r As Integer = 1 To 100
Dim pnum As Integer = Val(TextBox1.Text) ''Number of people
Dim days(pnum - 1) As Integer
Dim rnd As Random = New Random()
For i As Integer = 0 To (pnum - 1)
days(i) = rnd.Next(365)
Next
Dim count As Integer = 0
Dim inc As Integer = 0
Do
For inc = (count + 1) To (pnum - 1)
If count = (pnum - 1) Then
Exit For
End If
If days(count) = days(inc) Then
prc += 1 ''Match found
Exit Do
End If
Next
If count = (pnum - 1) Then
Exit Do
End If
count += 1
Loop
Next
MsgBox(prc)
End Sub
End Class
That's all the code. It searches for two matching random numbers from the set. This all repeats 100 times and it should count the results, but instead it only outputs 0 or 100.
source to share
The function has been rewritten here.
Public Shared rnum As New Random 'only one needed per application
Private Function myRand(h As Integer) As Integer
Dim num As Integer
num = rnum.Next(1, h) 'note maxValue is exclusive
Return num
End Function
From the documentation for Random, "The initial default is inferred from the system clock and has a finite resolution. As a result, different random objects that are created in close sequence by calling the default constructor will have the same initial default and will therefore produce identical sets random numbers ... "
This is why you have a problem. I also changed the name of the function because it matches the old Rnd method.
source to share
Even though a working solution has been given, I would like to explain "WHY"
your code did not behave as you expected.
When it comes to classical computing, there is no such thing as a truly random number.
The Random class generates a series of numbers based on a. seed value
When you don't pass this seed to the constructor, it will take system time as a seed.
The class constructor Random
lets you specify seed value
which one will be used.
Consider the following method:
Private Sub PrintRandomNumbers(seed As Integer, max As Integer)
Dim rnd = New Random(seed)
For i As Integer = 0 To 9
Console.Write("{0} ", rnd.Next(1, max))
Next
End Sub
This method takes seeds and maximum as parameters and then
instantiates an instance Random
with the specified value as its seed.
Every time you call this method with the same values ββfor "seed" and "max",
it will return accurate data, no matter how long it takes between method calls.
Public Sub Run()
For i As Integer = 0 To 4
PrintRandomNumbers(215668468, 365)
Console.WriteLine()
Thread.Sleep(1000)
Next
End Sub
On my system, this will output the following:
3223 2031 3014 1473 92 2612 1652 62 811 2103
3223 2031 3014 1473 92 2612 1652 62 811 2103
3223 2031 3014 1473 92 2612 1652 62 811 2103
3223 2031 3014 1473 92 2612 1652 62 811 2103
3223 2031 3014 1473 92 2612 1652 62 811 2103
I added a call to Thread.Sleep to show you that it is not time sensitive.
Different numbers should have been generated on your system, but the output will be the same for each iteration.
The only way to generate a different set of random numbers with a class Random
is to provide a different seed, min and / or max.
In your code, you've created a new instance of the class Random
in a very tight loop.
The code is executed so quickly that for each iteration the value seed
taken
from the system time was exactly the same, and as a result, the set of generated numbers was identical.
Think of the numbers generated by the class Random
as an infinite sequence of numbers.
At each iteration of the loop, you created a new instance and took the first number
that was generated. Which in the case of the above given example means "3223",
so every element of your array would be set to "3223"
The solutions suggested by other contributors work because they only
create one instance of the class Random
and reuse it over and over again.
As a result, at each iteration of the loop, they got the next number from the infinite sequence.
One thing to take away from you is something that you must always remember is Random
not random.
source to share
The following code will help you generate random numbers up to 365. Using a for loop I only display five of them in the message box, you can expand them by increasing the limit of the for loop.
Dim rnd As Random = New Random()
For i As Integer = 0 To 5
MsgBox(rnd.Next(365).ToString)
Next
source to share