【问题标题】:Why isn't this Random number generation code working?为什么这个随机数生成代码不起作用?
【发布时间】:2019-10-10 10:48:36
【问题描述】:

我正在编写一个程序来证明“生日悖论”。

    For i = 0 To (pnum - 1)
        days(i) = rnd(h:=365)
    Next

它为1到365之间的每个i(days(i))生成一个随机数,函数为:

    Private Function rnd(h As Integer)
    Dim num As Integer
    Dim rnum As Random
    rnum = New Random
    num = rnum.Next(1, h)
    Return num
    End Function

当我在 for 循环中添加一个断点并手动执行它时,它工作正常,但如果我 只需运行程序,它会在几天内将相同的随机数放入每个槽中(I)。

任何想法为什么?


数字生成现在可以工作了,但程序在使用断点调试时仍然以不同的方式工作。

Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Dim prc As Integer

    For r As Integer = 1 To 100
        Dim pnum As Integer = Val(TextBox1.Text) ''Number of people
        Dim days(pnum - 1) As Integer

        Dim rnd As Random = New Random()
        For i As Integer = 0 To (pnum - 1)
            days(i) = rnd.Next(365)
        Next


        Dim count As Integer = 0
        Dim inc As Integer = 0


        Do

            For inc = (count + 1) To (pnum - 1)
                If count = (pnum - 1) Then
                    Exit For
                End If
                If days(count) = days(inc) Then
                    prc += 1 ''Match found
                    Exit Do
                End If
            Next
            If count = (pnum - 1) Then
                Exit Do
            End If
            count += 1
        Loop

    Next

    MsgBox(prc)
End Sub
End Class

这就是全部代码。它所做的是从集合中搜索两个匹配的随机数。整个过程重复 100 次,它应该计算结果,但它只输出 0 或 100。

【问题讨论】:

标签: vb.net random birthday-paradox


【解决方案1】:

这里是重写的函数。

Public Shared rnum As New Random 'only one needed per application

Private Function myRand(h As Integer) As Integer
    Dim num As Integer
    num = rnum.Next(1, h) 'note maxValue is exclusive
    Return num
End Function

从 Random 的文档中,“默认种子值源自系统时钟并且具有有限的分辨率。因此,通过调用默认构造函数连续创建的不同 Random 对象将具有相同的默认种子值,因此会产生相同的随机数集..."

这就是您遇到上述问题的原因。我还更改了函数的名称,因为它与旧的 Rnd 方法匹配。

【讨论】:

    【解决方案2】:

    即使给出了可行的解决方案,我还是想解释一下“为什么”
    您的代码没有按照您预期的方式运行。

    说到经典计算,不存在真正的随机数。

    Random 类根据seed value 生成一系列数字
    当您不将此种子值传递给构造函数时,它将以系统时间作为种子。

    Random 类的构造函数允许您指定要使用的seed value

    考虑以下方法:

    Private Sub PrintRandomNumbers(seed As Integer, max As Integer)
        Dim rnd = New Random(seed)
    
        For i As Integer = 0 To 9
            Console.Write("{0} ", rnd.Next(1, max))
        Next
    End Sub
    

    此方法将种子和最大值作为参数,然后创建
    Random 的一个实例,以指定值作为其种子。

    每次调用此方法时,'seed' 和 'max' 的值都相同
    无论方法调用之间有多少时间,它都会输出完全相同的数据。

    Public Sub Run()
        For i As Integer = 0 To 4
            PrintRandomNumbers(215668468, 365)
            Console.WriteLine()
            Thread.Sleep(1000)
        Next
    End Sub
    

    在我的系统上,这将输出以下内容:

    3223 2031 3014 1473 92 2612 1652 62 811 2103
    3223 2031 3014 1473 92 2612 1652 62 811 2103
    3223 2031 3014 1473 92 2612 1652 62 811 2103
    3223 2031 3014 1473 92 2612 1652 62 811 2103
    3223 2031 3014 1473 92 2612 1652 62 811 2103
    

    我在示例中添加了对 Thread.Sleep 的调用,以表明它对时间不敏感。
    在您的系统上应该生成其他数字,但每次迭代的输出都是相同的。

    使用Random 类生成一组不同随机数的唯一方法
    是提供不同的种子、最小值和/或最大值。

    在您的代码中,您在一个非常紧凑的循环中创建了 Random 类的新实例。
    代码执行速度如此之快,以至于每次迭代都会采用 seed
    从系统时间是完全相同的,因此生成的数字集 是一样的。

    Random 类生成的数字视为无穷无尽的数字序列。
    在循环的每次迭代中,您都创建了一个新实例并获取了第一个数字
    那是生成的。在上面的示例数据中,这意味着值“3223”,
    所以你的数组的每个元素都会被设置为'3223'

    这里其他成员提供的解决方案有效,因为他们只
    创建 Random 类的单个实例并反复使用它。
    结果,在循环的每一次迭代中,他们都从无休止的序列中得到了下一个数字。

    要摆脱这一点的是,您应该始终记住Random 不是随机的。

    【讨论】:

    • 很难想象需要不同的伪随机数生成器 (PRNG) 的情况。如果在使其共享的类中使用它会照顾到这一点。对于测试播种 PRNG 可能很有用。
    • 加密和赌场软件跳到脑海,但你是对的,“共享”确实有帮助。我忘记了这一点,因为这是我 10 多年来编写的 VB 的第一行。我实际上不得不使用转换器来记住语法。
    【解决方案3】:

    以下代码将帮助您生成最大为 365 的随机数。使用 for 循环,我在消息框中仅显示其中五个,您可以通过增加 for 循环的限制来扩展它们。

        Dim rnd As Random = New Random()
        For i As Integer = 0 To 5
        MsgBox(rnd.Next(365).ToString)
        Next
    

    【讨论】:

      猜你喜欢
      • 2013-02-17
      • 1970-01-01
      • 2011-05-21
      • 2014-11-17
      • 2021-12-10
      • 1970-01-01
      • 2018-11-05
      • 2012-02-22
      • 2023-03-03
      相关资源
      最近更新 更多