代码之家  ›  专栏  ›  技术社区  ›  brendan

vb.net中的随机整数

  •  54
  • brendan  · 技术社区  · 16 年前

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

    我该怎么做?

    11 回复  |  直到 8 年前
        1
  •  52
  •   brendan    10 年前

    要获得介于1和n(包括1和n)之间的随机整数值,可以使用以下方法。

    CInt(Math.Ceiling(Rnd() * n)) + 1
    
        2
  •  65
  •   Dan Tao    14 年前

    正如已经多次指出的那样,编写这样的代码的建议是有问题的:

    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
    
        3
  •  32
  •   Joseph Sturtevant    10 年前

    使用 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)
    
        4
  •  5
  •   Shawn Kovac    10 年前

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

    微软让他们的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时,下一个函数将抛出一个错误。这可能是你想要的。但也可能不是。或者考虑当最小值为5,最大值为4时。通过添加1,5将传递给下一个方法,但它不会引发错误,当它确实是一个错误时,但我测试的Microsoft.NET代码返回5。因此,当max=min.时,它实际上不是一个“独占”的max,但是当random.next()函数的max<min时,它抛出argumentOutOfRangeException。因此,微软的实现在这方面也确实不一致,而且有缺陷。

    您可能只想在最小值和最大值之间交换数字,这样就不会产生错误,但这完全取决于需要什么。如果您希望在无效值上出现错误,那么在我们的代码中,当Microsoft的独占最大值(max+1)等于最小值时,最好也抛出错误,在这种情况下,MS不会出错。

    处理max=int32.maxvalue时的工作有点不方便,但我希望发布一个全面的函数来处理这两种情况。如果你想要不同于我编码的行为,那就适合你自己。但要注意这两个问题。

    快乐编码!

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

    ''' <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
    
        5
  •  4
  •   Bill the Lizard    14 年前
    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
    
        6
  •  2
  •   Wais    8 年前

    Microsoft示例 Rnd Function

    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))
    
        7
  •  1
  •   Rogala    10 年前

    如果你用的是约瑟夫的回答,这是一个很好的回答,你就这样把这些话背对背地说:

    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
    
        8
  •  1
  •   achar    9 年前

    您应该只创建一次伪随机数生成器:

    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
    

    随你的喜好。使用wrapper函数是合理的,因为最大值是排他的-我知道随机数是这样工作的,但是.next的定义很混乱。

    在我看来,每次需要一个数字时都创建一个生成器是错误的;伪随机数不能这样工作。

    首先,您会遇到初始化问题,这在其他回复中已经讨论过。如果初始化一次,就没有这个问题。

    第二,我一点也不确定你是否得到了一个有效的随机数序列;相反,你得到了多个不同序列的第一个数的集合,这些序列是根据计算机时间自动播种的。我不确定这些数字是否能通过确认序列随机性的测试。

        9
  •  0
  •   Binny    10 年前
    Dim rnd As Random = New Random
    rnd.Next(n)
    
        10
  •  0
  •   Zibri    8 年前

    仅供参考,用于RND和随机化的vb网络功能定义(应给出基本(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
    
        11
  •  -5
  •   patmortech    11 年前
    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
    

    [博伊斯] 这是最好的办法,从头开始: