I'm doing basic random number generation using this Shared Function:
Public Shared Function RandomNumber(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
'initialize random number generator
Dim r As New Random(Date.Now.Ticks And &HFFFF)
If MinNumber > MaxNumber Then
Dim t As Integer = MinNumber
MinNumber = MaxNumber
MaxNumber = t
End If
Return r.Next(MinNumber, MaxNumber)
End Function
Called like this: dim x as integer = Random(2100000000)
Very simple, and the seed value comes straight from a MS example.
HERE'S THE PROBLEM: I'm getting duplicate numbers on occasion, but always created at times that are usually at least 5 or 10 minutes apart. I can see if I was calling the function multiple times per second or millisecond, because that'd kind of "breaks" the seed. But these are showing up at extended time spans. What else could be causing this?
Duplicate seed issue?
It might be better defining r as static so that it is initialised once when first invoked. Refer to this answer Random integer in VB.NET
The Random constructor takes an Integer as its parameter which is 32-bits. As spencer7593 said, with only 16 bits, you're repeating the sequence every 6.5ms. Try:
Dim r As New Random(Date.Now.Ticks And &HFFFFFFFF)
However, this will do the same thing:
Dim r As New Random()
Better yet, don't create a new Random object each time:
Private Static r As New Random()
Public Shared Function RandomNumber(MaxNumber As Integer, Optional MinNumber As Integer = 0) As Integer
...
Return r.Next(MinNumber, MaxNumber)
End Function
Q: What else could be causing this?
A: It could be happening purely by random. Random numbers are just that: random. At any point in time, whether its seconds or hours away from another point in time, its just as likely for a number to appear as any other number. There is no guarantee that a number won't be repeated.
On the other hand, it looks like your seed value is only on the order of 16 bits. And that's like a total of 65,536 possibilities. There's 10,000 ticks in a millisecond, so ever 6.5 milliseconds you have the possibility of reusing the same seed.
It's not at all clear whether the VB Random is using some other kind of entropy beyond that seed or not. (But gathering entropy for inclusion would slow down the initialization, so it may not be, as a performance consideration.)
According the docs, creating two Random objects using the same seed value results in Random objects that create duplicate sequences of unique numbers.
http://msdn.microsoft.com/en-us/library/ctssatww.aspx
I think that answers the question why it is happening.
I guess the next question is why do you need to instantiate a new Random object? If you need multiple objects, then instantiating several of them, but making sure you are using a different seed value for each one would be one approach.
But before you go there, I recommend you consider using just one Random. Calls to get random numbers can be serviced from an existing Random, rather than creating a new one every time you need a random number.
Try it another way:
Public Function RandomNumber2(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer
' Initialize the random-number generator.
Randomize()
' Generate random value between MaxNumber and MinNumber.
Return CInt(Int((MaxNumber * Rnd()) + MinNumber))
End Function
See Randomize Function (Visual Basic) for more details. Hope this helps.
Related
It seems that Randomize() & Rnd() aren't used anymore.
Instead people make something like:
Dim rng as New Random()
Dim randomNo as Integer = rng.Next(10) ' this is a random number between 0 and 10.
Dim anotherRandomNo as Integer = rng.Next(10) ' a different random number.
Could someone tell me why this is considered "better" in most circumstances?
There are a few reasons.
Random has much greater functionality .. Have a look here
Also and more importantly the old Randomize is built into the instantiation of a Random object. By default, Rnd without randomize always started with the same seed number. If you didn't use randomize at the start of your program, each time it ran, it would generate the same sequence of numbers.
Finally, internally the Random object generates numbers in a different way with a better spread of randomness.
In my code,I have now realised I have to use the New Random function, my code was working before with the Randomize and then the numbers but now it comes up with loads of errors and wont even let me run the program. I think it is only a small error but I just need some help to get the final bit going
Heres the code and thanks for any help :)
I cannot get the code to work with the randomly generated number and I have to use the New Random function I cannot use randomize() Does anybody know how to help here is the code.
Dim timestook As Int32 = 1
Dim usersguess As Integer
Dim value = New Random(0 - 19)
Console.WriteLine("You have to guess this number. It is between 1 and 20. Good Luck !")
usersguess = Console.ReadLine()
'keep looping until they get the right value
While usersguess <> value
'now check how it compares to the random value
If usersguess < value Then
timestook = timestook + 1
Console.WriteLine("You're too low. Go higher ")
ElseIf usersguess > value Then
Console.WriteLine("You're too high. Go Lower.")
timestook = timestook + 1
End If
'If they are wrong the code will run again,after telling the user if they are too high or too low.
usersguess = Console.ReadLine()
End While
' Console.WriteLine("You're correct. Well Done")
If usersguess = value Then
Console.WriteLine("You took,{0}", timestook)
End If
Console.ReadLine()
End Sub
You'll want to do some googling on how to use random numbers. Your problem is that you aren't creating a Random object to handle the random number generation.
Here's how you can fix your code:
Dim randNumGen As New Random() 'Create Random object
Dim value As Integer = randNumGen.Next(0, 20) 'set value equal to a new random number between 0-19
Please note that this code could be further refactored for readability and simplicity (like changing timestook = timestook + 1 to timestook += 1 and selecting better variable names like numberOfGuesses as opposed to timestook, etc.
The expression New Random(0-19) does not do at all what you think it does, name it does NOT return an integer. Instead, it creates an instance of a Random object, which is a type that knows how to create new random values. The 0-19 part of the expression is the seed for the Random object's constructor, and is the same as just passing the value -19.
This looks like it's either homework or personal practice, so I feel like you will be better served in this case with a separate example using the Random type for reference than you would if I fixed the code sample in the question for you:
Dim rnd As New Random()
For i As Integer = 0 To 10
Console.WriteLine(rnd.Next(0, 20))
Next i
It's also worth mentioning here that you typically only want one Random object for your entire program, or at least only one Random object for each logical part of your program. Creating new Random objects resets the seeds, and for best results you want to follow the same seed on subsequent calls to the same instance for a while.
there has been many posts about this but nobody seems to have my problem.
I have a list box with letters a-z (line for each letter)
using
Dim rancon As New Random
Dim rc As Integer = ListBox1.Items.Count
Label5.Text = lcon.Items.Item(rancon.Next(rc)).ToString
all it is doing is chosing randomly, 1 of the first 7 or 8 characters.
can anyone advise?
I assume that you expect that the random always chooses a different item in the ListBox. Therefore you have to reuse the same Random instance since the default constructor derives the seed(which is used to initialize the pseudorandom number generator) from the current system time.
If you call this code very fast(for example in a loop), the seed will always be the same. Hence you get repeating numbers/items.
To avoid this you could make the Random a field in the class:
Private rancon As New Random
Public Sub YourMethod()
Dim rc As Integer = ListBox1.Items.Count
Label5.Text = ListBox1.Items(rancon.Next(rc)).ToString()
End Sub
MSDN:
The default seed value is derived from the system clock and has finite
resolution. As a result, different Random objects that are created in
close succession by a call to the default constructor will have
identical default seed values and, therefore, will produce identical
sets of random numbers. This problem can be avoided by using a single
Random object to generate all random numbers. You can also work around
it by modifying the seed value returned by the system clock and then
explicitly providing this new seed value to the Random(Int32)
constructor.
Note that i've also used ListBox1.Items instead of lcon.Items in case that was a typo.
So basically, I have this function that is supposed to generate two random integers between a high and a low number, to make a point on the form. I know that Random can handle this, but Random has consistency, whereas I need the numbers to be completely random on the form.
For example, most of my generated points appear in a diagonal line. This is what I want to avoid. It should go all over the form between the high and low numbers.
Here is my current function:
Function GetNewLocation() As Point
Randomize()
Dim int1 As Integer = RandomNumber(6, 345)
Randomize()
Dim int2 As Integer = RandomNumber(35, 286)
Return New Point(int1, int2)
End Function
Function RandomNumber(ByVal low As Integer, ByVal high As Integer) As Integer
Randomize()
Return New Random().Next(low, high)
End Function
How can I get true random number generation where the point is not on a diagonal line?
Each time you create a new instance of Random you are resetting the random number generator. Since the default constructor uses Environment.TickCount as the seed you are often returning precisely the same sequence of pseudo-random numbers. The system does not update TickCount that often. This is why it seems to you that you are getting non-random numbers.
Try changing your code like this:
Private _rnd As New Random()
Function RandomNumber(ByVal low As Integer, ByVal high As Integer) As Integer
Return _rnd.Next(low, high)
End Function
There is no true randomness in computer systems. There are many algorithm to generate "random" numbers but they are always based on a seed, like the time, process id, a mix of both, or on more advanced cases where randomness is taken seriously, on sounds being detected in a microphone, data from atmospheric sensors or cosmic microwave background, but it will always derivate from some existing source of information.
Thats also not the best slution.
I prefer my own code:
Dim old As Integer = 6572
Public Function Rand(ByVal min As Integer, ByVal max As Integer) As Integer
Dim random As New Random(old + Date.Now.Millisecond)
old = random.Next(min, max + CInt(IIf(Date.Now.Millisecond Mod 2 = 0, 1, 0)))
Return old
End Function
Thats a little bit better
I literally just came up with this solution. Maybe it will help =)
I went from:
Dim rand As Random = New Random(DateTime.Now.Millisecond)
To
Dim rand As Random = New Random(DateTime.Now.Millisecond * DateTime.Now.Second * DateTime.Now.Minute * DateTime.Now.Hour)
And it seems to have worked really well.
You can see the difference in the side by side.
in java(assuming the limit is (limit-1)):
random = System.currentTimeMillis()%limit;
You get the idea :)
I have previously been told that I should always use Randomize() before I use Rnd() in a VB.NET application. Yet, it always seems to work fine without it. What does adding Randomize() do for me in this case?
It doesn't appear to affect my application in the least.
In Visual Basic, Rnd() uses a mathematical operation to produce the next "random" number. Because the actual operation is known, given a specific value, you can predict the next value. However, given an arbitray start value the numbers have good distribution - these are "pseudo-random" numbers.
To keep Rnd() from startng at a predictable number (and hence giving the same sequence of "random" numbers every time), Randomize() should be called to use the machine clock to set the initial value (called a seed).
(In the .NET world, I'd use System.Random instead if you can.)
Randomize() initializes the first seed of Rnd(). If you won't use it - VB.NET will use the default seed number.
Randomize will set the seed to something time related, like the system uptime or the system date. So the function Rand() will show different values every time the app is executed. However, I highly recommend you to use the System.Random class instead of VisualBasic Rand(). No need to call any randomize() function
Here are some example code, this will generate six random integers from the lower to upper bounds:
Dim randObj As New Random( seed )
Dim j As Integer
For j = 0 To 5
Console.Write( "{0,11} ", randObj.Next( lower, upper ) )
Next j
Console.WriteLine( )