VB.NET中的随机整数
我需要生成一个1到n之间的随机整数(其中n是一个正整数)用于unit testing。 我不需要太复杂的东西来确保真正的随机性 – 只是一个老式的随机数。
我该怎么做?
要获得1和N(包含)之间的随机整数值,可以使用以下内容。
CInt(Math.Ceiling(Rnd() * n)) + 1
正如已经多次指出的那样,编写这样的代码的build议是有问题的:
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
原因是Random
类的构造函数提供了一个基于系统时钟的默认种子。 在大多数系统中,这个粒度是有限的 – 在20ms附近。 所以如果你写下面的代码,你会连续得到相同的数字:
Dim randoms(1000) As Integer For i As Integer = 0 to randoms.Length - 1 randoms(i) = GetRandom(1, 100) Next
以下代码解决了此问题:
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
我用这两种方法把一个简单的程序放在一起,产生了1到100之间的25个随机整数。下面是输出:
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
使用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)
到目前为止所有的答案都有问题或错误(复数,而不只是一个)。 我会解释。 但首先,我要赞扬陶涛的见解,使用一个静态variables来记住Generatorvariables,所以多次调用它不会重复同样的#,并且给出了一个很好的解释。 但是,正如我现在所解释的那样,他的代码也遭受了大多数人的同样的瑕疵。
MS使他们的Next()方法相当奇怪。 Min参数是人们所期望的包含最小值,但是Max参数是不能预期的排他最大值。 换句话说,如果你传递min = 1和max = 5,那么你的随机数将是1,2,3或4中的任何一个,但是它永远不会包含5.这是所有代码中两个潜在错误中的第一个使用微软的Random.Next()方法。
对于一个简单的答案(但仍然与其他可能的但罕见的问题),那么你需要使用:
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
(我喜欢使用Int32
而不是Integer
因为它更清楚int的大小,加上input的时间更短,但适合自己。)
我发现这种方法存在两个潜在的问题,但是对于大多数的应用来说,它是合适的(并且是正确的)。 所以如果你想要一个简单的解决scheme,我相信这是正确的。
唯一的两个问题,我看到这个function是:1:当Max = Int32.MaxValue,所以加1创build一个数值溢出。 虽然如此,这将是罕见的,这仍然是一种可能性。 2:当min> max + 1时,当min = 10且max = 5时,Next函数抛出一个错误。 这可能是你想要的。 但也可能不是。 或考虑当min = 5和max = 4时,通过添加1,5传递给Next方法,但它不会抛出一个错误,当它真的是一个错误,但我testing的Microsoft .NET代码返回5当最大值=最小值时,它确实不是“独占”最大值。 但是如果Random.Next()函数的max <min,则会抛出一个ArgumentOutOfRangeExceptionexception。 所以微软的实现在这方面也是非常不一致的。
您可能只需要在min> max时交换数字,以免引发错误,但完全取决于所需的数据。 如果你想在无效值上出现错误,那么当我们的代码中微软的独占最大值(max + 1)等于最小值时,也可能抛出错误,在这种情况下,MS不会出错。
处理max = Int32.MaxValue时的解决方法有点不方便,但我期望发布一个彻底的函数来处理这两种情况。 如果你想要不同的行为,而不是我如何编码它,适合自己。 但要注意这两个问题。
快乐的编码!
编辑:所以我需要一个随机的整数发生器,我决定编写它'正确'。 所以如果任何人想要完整的function,这是一个实际工作。 (但是,只用2行代码就不能赢得最简单的奖品,但也不是很复杂)。
''' <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's 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
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
如果你正在使用约瑟夫的答案,这是一个很好的答案,你可以像这样背对背地回答:
dim i = GetRandom(1, 1715) dim o = GetRandom(1, 1715)
然后结果可能会一遍又一遍地重复,因为它很快地处理了呼叫。 这在08年可能不是什么问题,但是由于今天的处理器速度要快得多,所以在进行第二次通话之前,该function不允许系统时钟有足够的时间进行更改。
由于System.Random()函数是基于系统时钟的,因此我们需要留出足够的时间在下一次调用之前进行更改。 完成这个的一种方法是暂停当前线程1毫秒。 看下面的例子:
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
你应该只创build一个伪随机数发生器:
Dim Generator As System.Random = New System.Random()
那么,如果一个整数足够你的需要,你可以使用:
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
尽可能多的时间,你喜欢。 使用包装函数是有道理的,因为最大值是独占的 – 我知道随机数的工作方式,但。Next的定义是混乱。
每次你需要一个数字时创build一个发生器在我看来是错误的; 伪随机数字不这样工作。
首先,您遇到了其他答复中讨论过的初始化问题。 如果初始化一次,则不存在此问题。
其次,我不能确定你得到了一个有效的随机数列; 相反,你会得到第一批多个不同序列的集合,这些序列是根据计算机时间自动播种的。 我不确定这些数字是否会通过确认序列随机性的testing。
Microsoft示例Rnd函数
https://msdn.microsoft.com/en-us/library/f7s023d2%28v=vs.90%29.aspx
1-初始化随机数发生器。
Randomize()
2 – 生成1到6之间的随机值。
Dim value As Integer = CInt(Int((6 * Rnd()) + 1))
Dim rnd As Random = New Random rnd.Next(n)
仅供参考,用于RND和RANDOMIZE的VB NET Fuction定义(其应该给出与BASIC(1980年)相同的结果并且之后的所有版本是:
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
而随机类是:
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
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]这是从头开始的最好的方式:P