3

「誕生日のパラドックス」を証明するプログラムを書いています。

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

i (days(i))1 から 365までの乱数を生成します。関数は次のとおりです。

    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

それがコード全体です。それが行うことは、セットから 2 つの一致する乱数を検索することです。全体が 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 クラスは一連の数値を生成し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」に設定されます

ここで他のメンバーによって提供されるソリューション
は、クラスのインスタンスを 1 つしか作成せずRandom、何度も再利用するため機能します。
その結果、ループの反復ごとに、エンドレス シーケンスから次の番号を取得しました。

Randomここから取り除かなければならないことの 1 つは、ランダムではないことを常に覚えておく必要があるということです。

于 2014-08-03T15:19:05.933 に答える
0

次のコードは、最大 365 の乱数を生成するのに役立ちます。 for ループを使用して、メッセージ ボックスに 5 つだけを表示しました。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 に答える