3

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

    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。

4

3 回答 3

4

这是重写的函数。

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 方法匹配。

于 2014-08-03T14:57:33.600 回答
3

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

归结为经典计算,不存在真正的随机数。

Random 类基于 a 生成一系列数字。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这不是随机的。

于 2014-08-03T15:19:05.933 回答
0

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

    Dim rnd As Random = New Random()
    For i As Integer = 0 To 5
    MsgBox(rnd.Next(365).ToString)
    Next
于 2014-08-03T14:39:11.923 回答