Random integer in VB.NET

I need to create a random integer from 1 to n (where n is a positive integer) to use with a unit test. I don't need something too complex to provide true randomness - just an old-fashioned random number.

How should I do it?

+49
random
Aug 20 '08 at 19:54
source share
11 answers

To get a random integer value between 1 and N (inclusive), you can use the following.

CInt(Math.Ceiling(Rnd() * n)) + 1 
+45
Aug 20 '08 at 19:55
source share

As has been repeatedly stated, the proposal to write such code is problematic:

 Public Function GetRandom(ByVal Min As Integer, ByVal Max As Integer) As Integer Dim Generator As System.Random = New System.Random() Return Generator.Next(Min, Max) End Function 

The reason is that the constructor for the Random class provides an initial default value based on the system clock. On most systems, this has limited granularity β€” somewhere around 20 ms. Therefore, if you write the following code, you will receive the same number several times in a row:

 Dim randoms(1000) As Integer For i As Integer = 0 to randoms.Length - 1 randoms(i) = GetRandom(1, 100) Next 

The following code fixes this problem:

 Public Function GetRandom(ByVal Min As Integer, ByVal Max As Integer) As Integer ' by making Generator static, we preserve the same instance ' ' (ie, do not create new instances with the same seed over and over) ' ' between calls ' Static Generator As System.Random = New System.Random() Return Generator.Next(Min, Max) End Function 

I put together a simple program using both methods to generate 25 random numbers from 1 to 100. Here's the output:

 Non-static: 70 Static: 70 Non-static: 70 Static: 46 Non-static: 70 Static: 58 Non-static: 70 Static: 19 Non-static: 70 Static: 79 Non-static: 70 Static: 24 Non-static: 70 Static: 14 Non-static: 70 Static: 46 Non-static: 70 Static: 82 Non-static: 70 Static: 31 Non-static: 70 Static: 25 Non-static: 70 Static: 8 Non-static: 70 Static: 76 Non-static: 70 Static: 74 Non-static: 70 Static: 84 Non-static: 70 Static: 39 Non-static: 70 Static: 30 Non-static: 70 Static: 55 Non-static: 70 Static: 49 Non-static: 70 Static: 21 Non-static: 70 Static: 99 Non-static: 70 Static: 15 Non-static: 70 Static: 83 Non-static: 70 Static: 26 Non-static: 70 Static: 16 Non-static: 70 Static: 75 
+59
Apr 20 '10 at 18:57
source share

Use System.Random :

 Dim MyMin As Integer = 1, MyMax As Integer = 5, My1stRandomNumber As Integer, My2ndRandomNumber As Integer ' Create a random number generator Dim Generator As System.Random = New System.Random() ' Get a random number >= MyMin and <= MyMax My1stRandomNumber = Generator.Next(MyMin, MyMax + 1) ' Note: Next function returns numbers _less than_ max, so pass in max + 1 to include max as a possible value ' Get another random number (don't create a new generator, use the same one) My2ndRandomNumber = Generator.Next(MyMin, MyMax + 1) 
+32
Aug 20 '08 at 20:00
source share

All answers still have problems or errors (plural, not just one). I will explain. But first, I want to praise Dan Tao to use the static variable to remember the Generator variable, so repeating it repeatedly will not repeat the same # again and again, plus he gave a very good explanation. But his code suffered the same flaw as most others, as I now explain.

MS made its Next () method pretty odd. the Min parameter is an inclusive minimum, as you would expect, but the Max parameter is an exclusive maximum that would not be expected. in other words, if you pass min = 1 and max = 5, then your random numbers will be any of 1, 2, 3 or 4, but it will never include 5. This is the first of two potential errors in the whole code, uses the Microsoft method Random.Next ().

For a simple answer (but still with other possible but rare problems) you will need to use:

 Private Function GenRandomInt(min As Int32, max As Int32) As Int32 Static staticRandomGenerator As New System.Random Return staticRandomGenerator.Next(min, max + 1) End Function 

(I like to use Int32 , not Integer , because it makes it clearer how big the int is, plus it is shorter, but suits you yourself.)

I see two potential problems with this method, but it will be suitable (and correct) for most applications. Therefore, if you want a simple solution, I believe that this is correct.

The only 2 problems that I see with this function are: 1: when Max = Int32.MaxValue, so adding 1 creates a numerical overflow. altho, that would be rare, it is still possible. 2: when min> max + 1, when min = 10 and max = 5, the Next function throws an error. it may be what you want. but it may not be. or consider when min = 5 and max = 4. By adding 1, 5 the Next method is passed, but it does not throw an error when it really is an error, but the Microsoft.NET code I tested returns 5. so it really is not "exclusive "maximum when max = min. but when max <min for the Random.Next () function, then it throws an ArgumentOutOfRangeException. therefore, the Microsoft implementation is actually inconsistent and erroneous in this regard.

you can just change the numbers at min> max so that there are no errors, but it completely depends on what you want. if you need an error with invalid values, then it is probably better to throw an error when the exclusive Microsoft maximum (max + 1) in our code is equal to the minimum where MS cannot make an error in this case.

processing a workflow when max = Int32.MaxValue is a bit inconvenient, but I expect to post a full function that handles both of these situations. and if you need a different behavior than the way I encoded it, come on. but keep these 2 issues in mind.

Happy coding!

Edit: So I need a random number generator, and I decided to encode it β€œcorrectly”. Therefore, if someone wants to get full functionality, then here that really works. (But he does not win the simplest prize with only two lines of code, but he is also not very complicated.)

 ''' <summary> ''' Generates a random Integer with any (inclusive) minimum or (inclusive) maximum values, with full range of Int32 values. ''' </summary> ''' <param name="inMin">Inclusive Minimum value. Lowest possible return value.</param> ''' <param name="inMax">Inclusive Maximum value. Highest possible return value.</param> ''' <returns></returns> ''' <remarks></remarks> Private Function GenRandomInt(inMin As Int32, inMax As Int32) As Int32 Static staticRandomGenerator As New System.Random If inMin > inMax Then Dim t = inMin : inMin = inMax : inMax = t If inMax < Int32.MaxValue Then Return staticRandomGenerator.Next(inMin, inMax + 1) ' now max = Int32.MaxValue, so we need to work around Microsoft quirk of an exclusive max parameter. If inMin > Int32.MinValue Then Return staticRandomGenerator.Next(inMin - 1, inMax) + 1 ' okay, this was the easy one. ' now min and max give full range of integer, but Random.Next() does not give us an option for the full range of integer. ' so we need to use Random.NextBytes() to give us 4 random bytes, then convert that to our random int. Dim bytes(3) As Byte ' 4 bytes, 0 to 3 staticRandomGenerator.NextBytes(bytes) ' 4 random bytes Return BitConverter.ToInt32(bytes, 0) ' return bytes converted to a random Int32 End Function 
+5
Jan 30 '14 at
source share
 Public Function RandomNumber(ByVal n As Integer) As Integer 'initialize random number generator Dim r As New Random(System.DateTime.Now.Millisecond) Return r.Next(1, n) End Function 
+4
Aug 20 '08 at 19:59
source share

If you use Joseph's answer, which is a great answer, and you run them back to the back, like this:

 dim i = GetRandom(1, 1715) dim o = GetRandom(1, 1715) 

Then the result can be repeated again and again, because it processes the call so quickly. Perhaps this was not a problem in '08, but since processors are much faster today, the function does not allow the system clock enough time to change until the second call.

Since the System.Random () function is based on the system clock, we need to allow enough time to change it until the next call. One way to achieve this is to pause the current thread for 1 millisecond. See the example below:

 Public Function GetRandom(ByVal min as Integer, ByVal max as Integer) as Integer Static staticRandomGenerator As New System.Random max += 1 Return staticRandomGenerator.Next(If(min > max, max, min), If(min > max, min, max)) End Function 
+1
Oct 24 '13 at 13:48 on
source share

You need to create a pseudo random number generator only once:

 Dim Generator As System.Random = New System.Random() 

Then, if an integer is sufficient for your needs, you can use:

 Public Function GetRandom(myGenerator As System.Random, ByVal Min As Integer, ByVal Max As Integer) As Integer 'min is inclusive, max is exclusive (dah!) Return myGenerator.Next(Min, Max + 1) End Function 

as many times as you want. Using the wrapper function is justified only because the maximum value is exceptional - I know that random numbers work this way, but the definition of .Next is confusing.

Creating a generator every time you need a number is wrong in my opinion; pseudo random numbers do not work this way.

Firstly, you get an initialization problem, which was discussed in other answers. If you initialize once, you do not have this problem.

Secondly, I'm not at all sure that you will get a valid sequence of random numbers; rather, you get a collection of the first number of several different sequences that are seeded automatically based on computer time. I am not sure that these numbers will pass tests confirming the randomness of the sequence.

+1
Aug 17 '15 at 6:25
source share

Microsoft Example Rnd Function

https://msdn.microsoft.com/en-us/library/f7s023d2%28v=vs.90%29.aspx

1- Initialize the random number generator.

 Randomize() 

2 - Generate a random value between 1 and 6.

 Dim value As Integer = CInt(Int((6 * Rnd()) + 1)) 
+1
Feb 22 '16 at 20:38
source share
 Dim rnd As Random = New Random rnd.Next(n) 
0
Dec 01 '14 at 12:03 on
source share

For reference, the definition of VB NET Fuction for RND and RANDOMIZE (which should give the same BASIC results (1980 years) and all versions after:

 Public NotInheritable Class VBMath ' Methods Private Shared Function GetTimer() As Single Dim now As DateTime = DateTime.Now Return CSng((((((60 * now.Hour) + now.Minute) * 60) + now.Second) + (CDbl(now.Millisecond) / 1000))) End Function Public Shared Sub Randomize() Dim timer As Single = VBMath.GetTimer Dim projectData As ProjectData = ProjectData.GetProjectData Dim rndSeed As Integer = projectData.m_rndSeed Dim num3 As Integer = BitConverter.ToInt32(BitConverter.GetBytes(timer), 0) num3 = (((num3 And &HFFFF) Xor (num3 >> &H10)) << 8) rndSeed = ((rndSeed And -16776961) Or num3) projectData.m_rndSeed = rndSeed End Sub Public Shared Sub Randomize(ByVal Number As Double) Dim num2 As Integer Dim projectData As ProjectData = ProjectData.GetProjectData Dim rndSeed As Integer = projectData.m_rndSeed If BitConverter.IsLittleEndian Then num2 = BitConverter.ToInt32(BitConverter.GetBytes(Number), 4) Else num2 = BitConverter.ToInt32(BitConverter.GetBytes(Number), 0) End If num2 = (((num2 And &HFFFF) Xor (num2 >> &H10)) << 8) rndSeed = ((rndSeed And -16776961) Or num2) projectData.m_rndSeed = rndSeed End Sub Public Shared Function Rnd() As Single Return VBMath.Rnd(1!) End Function Public Shared Function Rnd(ByVal Number As Single) As Single Dim projectData As ProjectData = ProjectData.GetProjectData Dim rndSeed As Integer = projectData.m_rndSeed If (Number <> 0) Then If (Number < 0) Then Dim num1 As UInt64 = (BitConverter.ToInt32(BitConverter.GetBytes(Number), 0) And &HFFFFFFFF) rndSeed = CInt(((num1 + (num1 >> &H18)) And CULng(&HFFFFFF))) End If rndSeed = CInt((((rndSeed * &H43FD43FD) + &HC39EC3) And &HFFFFFF)) End If projectData.m_rndSeed = rndSeed Return (CSng(rndSeed) / 1.677722E+07!) End Function End Class 

While Random CLASS:

 Public Class Random ' Methods <__DynamicallyInvokable> _ Public Sub New() Me.New(Environment.TickCount) End Sub <__DynamicallyInvokable> _ Public Sub New(ByVal Seed As Integer) Me.SeedArray = New Integer(&H38 - 1) {} Dim num4 As Integer = If((Seed = -2147483648), &H7FFFFFFF, Math.Abs(Seed)) Dim num2 As Integer = (&H9A4EC86 - num4) Me.SeedArray(&H37) = num2 Dim num3 As Integer = 1 Dim i As Integer For i = 1 To &H37 - 1 Dim index As Integer = ((&H15 * i) Mod &H37) Me.SeedArray(index) = num3 num3 = (num2 - num3) If (num3 < 0) Then num3 = (num3 + &H7FFFFFFF) End If num2 = Me.SeedArray(index) Next i Dim j As Integer For j = 1 To 5 - 1 Dim k As Integer For k = 1 To &H38 - 1 Me.SeedArray(k) = (Me.SeedArray(k) - Me.SeedArray((1 + ((k + 30) Mod &H37)))) If (Me.SeedArray(k) < 0) Then Me.SeedArray(k) = (Me.SeedArray(k) + &H7FFFFFFF) End If Next k Next j Me.inext = 0 Me.inextp = &H15 Seed = 1 End Sub Private Function GetSampleForLargeRange() As Double Dim num As Integer = Me.InternalSample If ((Me.InternalSample Mod 2) = 0) Then num = -num End If Dim num2 As Double = num num2 = (num2 + 2147483646) Return (num2 / 4294967293) End Function Private Function InternalSample() As Integer Dim inext As Integer = Me.inext Dim inextp As Integer = Me.inextp If (++inext >= &H38) Then inext = 1 End If If (++inextp >= &H38) Then inextp = 1 End If Dim num As Integer = (Me.SeedArray(inext) - Me.SeedArray(inextp)) If (num = &H7FFFFFFF) Then num -= 1 End If If (num < 0) Then num = (num + &H7FFFFFFF) End If Me.SeedArray(inext) = num Me.inext = inext Me.inextp = inextp Return num End Function <__DynamicallyInvokable> _ Public Overridable Function [Next]() As Integer Return Me.InternalSample End Function <__DynamicallyInvokable> _ Public Overridable Function [Next](ByVal maxValue As Integer) As Integer If (maxValue < 0) Then Dim values As Object() = New Object() { "maxValue" } Throw New ArgumentOutOfRangeException("maxValue", Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", values)) End If Return CInt((Me.Sample * maxValue)) End Function <__DynamicallyInvokable> _ Public Overridable Function [Next](ByVal minValue As Integer, ByVal maxValue As Integer) As Integer If (minValue > maxValue) Then Dim values As Object() = New Object() { "minValue", "maxValue" } Throw New ArgumentOutOfRangeException("minValue", Environment.GetResourceString("Argument_MinMaxValue", values)) End If Dim num As Long = (maxValue - minValue) If (num <= &H7FFFFFFF) Then Return (CInt((Me.Sample * num)) + minValue) End If Return (CInt(CLng((Me.GetSampleForLargeRange * num))) + minValue) End Function <__DynamicallyInvokable> _ Public Overridable Sub NextBytes(ByVal buffer As Byte()) If (buffer Is Nothing) Then Throw New ArgumentNullException("buffer") End If Dim i As Integer For i = 0 To buffer.Length - 1 buffer(i) = CByte((Me.InternalSample Mod &H100)) Next i End Sub <__DynamicallyInvokable> _ Public Overridable Function NextDouble() As Double Return Me.Sample End Function <__DynamicallyInvokable> _ Protected Overridable Function Sample() As Double Return (Me.InternalSample * 4.6566128752457969E-10) End Function ' Fields Private inext As Integer Private inextp As Integer Private Const MBIG As Integer = &H7FFFFFFF Private Const MSEED As Integer = &H9A4EC86 Private Const MZ As Integer = 0 Private SeedArray As Integer() End Class 
0
Oct 09 '16 at 21:06
source share
 Function xrand() As Long Dim r1 As Long = Now.Day & Now.Month & Now.Year & Now.Hour & Now.Minute & Now.Second & Now.Millisecond Dim RAND As Long = Math.Max(r1, r1 * 2) Return RAND End Function 

[BBOYSE] This is the best way, from scratch: P

-5
Nov 01. '12 at 16:16
source share



All Articles