VB.NET中的随机整数

VB.NET中的随机整数,vb.net,random,Vb.net,Random,我需要生成一个介于1和n之间的随机整数(其中n是一个正整数)用于单元测试。我不需要太复杂的东西来确保真正的随机性——只需要一个老式的随机数 我该怎么做?要获得1到N(包括)之间的随机整数值,可以使用以下公式 CInt(Math.Ceiling(Rnd() * n)) + 1 使用: Dim MyMin为整数=1,MyMax为整数=5,My1stRandomNumber为整数,My2ndRandomNumber为整数 '创建一个随机数生成器 作为System.Random的Dim生成器=新Sys

我需要生成一个介于1和n之间的随机整数(其中n是一个正整数)用于单元测试。我不需要太复杂的东西来确保真正的随机性——只需要一个老式的随机数


我该怎么做?

要获得1到N(包括)之间的随机整数值,可以使用以下公式

CInt(Math.Ceiling(Rnd() * n)) + 1
使用:

Dim MyMin为整数=1,MyMax为整数=5,My1stRandomNumber为整数,My2ndRandomNumber为整数
'创建一个随机数生成器
作为System.Random的Dim生成器=新System.Random()

'获取一个随机数>=MyMin和,正如已经多次指出的那样,这样编写代码的建议是有问题的:

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
类的构造函数提供了基于系统时钟的默认种子。在大多数系统上,这是有限的粒度——大约20毫秒。因此,如果您编写以下代码,您将在一行中多次获得相同的数字:

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 '
    ' (i.e., 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
我编写了一个简单的程序,使用这两种方法生成25个1到100之间的随机整数。以下是输出:

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
[b博伊斯]
这是最好的方法,从头开始:P

如果你使用约瑟夫的答案,这是一个很好的答案,并且你像这样背靠背地运行这些:

dim i = GetRandom(1, 1715)
dim o = GetRandom(1, 1715)
然后结果可能会一次又一次地返回相同的结果,因为它处理呼叫的速度非常快。这在08年可能不是一个问题,但由于处理器现在快得多,该函数不允许系统时钟在进行第二次调用之前有足够的时间进行更改

由于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

到目前为止,所有的答案都有问题或bug(复数,而不仅仅是一个)。我会解释的。但首先我要赞扬Dan Tao的洞察力,他使用静态变量来记住生成器变量,因此多次调用它不会重复相同的内容,而且他给出了非常好的解释。但正如我现在解释的那样,他的代码和大多数其他代码都有同样的缺陷

MS使他们的Next()方法相当奇怪。Min参数是预期的包含最小值,但Max参数是预期的不包含最大值。换句话说,如果你通过min=1和max=5,那么你的随机数将是1、2、3或4中的任何一个,但它永远不会包括5。这是使用Microsoft的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有多大,加上它的键入时间更短,但适合您自己。)

我发现这个方法有两个潜在的问题,但它适合(并且正确)大多数应用。所以如果你想要一个简单的解决方案,我相信这是正确的

我认为该函数仅有两个问题: 1:当Max=Int32.MaxValue时,因此添加1会创建数字溢出。虽然这很少见,但还是有可能的。 2:当最小值>最大值+1时。当min=10和max=5时,下一个函数抛出一个错误。这可能是你想要的。但也可能不是这样。或者考虑当min=5和max=4时。通过添加1,5被传递到下一个方法,但它不会抛出错误(当它确实是错误时),但我测试的Microsoft.NET代码返回5。因此,当max=min时,它实际上不是一个“排他的”max。但是当Random.Next()函数的max 您可能希望在min>max时简单地交换数字,这样就不会抛出错误,但这完全取决于需要什么。如果您希望在无效值上出错,那么最好在我们的代码中Microsoft的独占最大值(max+1)等于最小值时也抛出该错误,在这种情况下MS不会出错

处理max=Int32.MaxValue时的变通方法有点不方便,但我希望发布一个全面的函数来处理这两种情况。如果你想要不同于我编码的行为,那就随你便吧。但要注意这两个问题

快乐编码

编辑: 所以我需要一个随机整数生成器,我决定将其编码为“正确”。因此,如果有人想要完整的功能,这里有一个真正有效的。(但它并没有因为只有两行代码而赢得最简单的奖项。但它也不是很复杂。)

“”
''生成一个随机整数,该整数具有任何(包括)最小值或(包括)最大值,并具有完整的Int32值范围。
''' 
''包括最小值。最低可能返回值。
''包括最大值。可能的最高返回值。
''' 
''' 
专用函数GenRandomInt(inMin为Int32,inMax为Int32)为Int32
作为新系统的静态随机发生器。随机
如果inMin>inMax,则尺寸t=inMin:inMin=inMax:inMax=t
如果inMaxInt32.MinValue,则返回staticRandomGenerator.Next(inMin-1,inMax)+1'好的,这是一个简单的方法。
'现在,min和max给出了整数的完整范围,但Random.Next()没有给我们提供整数的完整范围的选项。
'所以我们需要使用Random.NextBytes()给我们4个随机字节,然后将其转换为随机整数。
Dim字节(3)作为字节'4字节,0到3
staticRandomGenerator.NextBytes(字节)'4个随机字节
Return BitConverter.ToInt32(字节,0)'返回转换为随机Int32的字节
端函数
dim i = GetRandom(1, 1715)
dim o = GetRandom(1, 1715)
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
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
''' <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
Dim rnd As Random = New Random
rnd.Next(n)
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
Randomize()
Dim value As Integer = CInt(Int((6 * Rnd()) + 1))
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