質問

単体テストに使用するために、1 から n (n は正の整数) までのランダムな整数を生成する必要があります。真のランダム性を保証するために過度に複雑なものは必要ありません。昔ながらの乱数だけです。

どうすればいいでしょうか?

役に立ちましたか?

解決

1 から N (両端を含む) までのランダムな整数値を取得するには、次を使用できます。

CInt(Math.Ceiling(Rnd() * n)) + 1

他のヒント

何度も指摘されているように、次のようなコードを書くという提案には問題があります。

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

両方の方法を使用して、1 から 100 までの 25 個のランダムな整数を生成する簡単なプログラムを作成しました。出力は次のとおりです。

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

使用 システム.ランダム:

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)

これまでのすべての回答には問題またはバグがあります (1 つだけではなく複数)。説明させていただきます。しかし、最初に、静的変数を使用して Generator 変数を記憶するという Dan Tao の洞察力を褒めたいと思います。これにより、それを複数回呼び出しても、同じ # を何度も繰り返すことがなくなります。さらに、彼は非常に素晴らしい説明をしてくれました。しかし、今説明するように、彼のコードには他のほとんどのコードと同じ欠陥がありました。

MS は Next() メソッドをかなり奇妙にしました。Min パラメータは予想どおり包括的な最小値ですが、Max パラメータは エクスクルーシブ 予想外の最大値です。つまり、min=1 と max=5 を渡すと、乱数は 1、2、3、または 4 のいずれかになりますが、5 が含まれることはありません。これは、Microsoft の Random.Next() メソッドを使用するすべてのコードに存在する 2 つの潜在的なバグのうちの 1 つ目です。

のために 単純 答え(ただし、他の可能性はありますがまれな問題が発生する可能性があります)の場合は、次のように使用する必要があります。

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 の大きさがより明確になり、入力も短くなりますが、自分に合ったものを選択してください)。

この方法には潜在的な問題が 2 つありますが、ほとんどの用途には適しています (そして正しい)。それで、あなたが欲しいなら、 単純 解決策、これが正しいと思います。

この関数で私が確認した問題は次の 2 つだけです。1:Max = Int32.MaxValue の場合、1 を追加すると数値オーバーフローが発生します。ただし、これはまれですが、可能性はまだあります。2:最小値 > 最大値 + 1 の場合。min = 10 および max = 5 の場合、Next 関数はエラーをスローします。これがあなたが望むものかもしれません。しかし、それはどちらでもないかもしれません。または、最小 = 5 および最大 = 4 の場合を検討してください。1 を追加すると、5 が Next メソッドに渡されますが、実際にはエラーである場合はエラーはスローされませんが、テストした Microsoft .NET コードは 5 を返します。したがって、最大値 = 最小値である場合、それは実際には「排他的な」最大値ではありません。ただし、Random.Next() 関数の max < min の場合、ArgumentOutOfRangeException がスローされます。したがって、この点に関しても、Microsoft の実装は非常に一貫性がなく、バグが多いです。

min > max の場合、エラーがスローされないように単純に数値を交換することもできますが、それは何を望むかによって完全に異なります。無効な値に関するエラーが必要な場合は、コード内の Microsoft の独自の最大値 (max + 1) が最小値に等しい場合にもエラーをスローする方がよいでしょう。この場合、MS はエラーに失敗します。

max = Int32.MaxValue の場合の回避策の処理は少し不便ですが、これらの両方の状況を処理する完全な関数を投稿することを期待しています。私がコーディングした方法とは異なる動作が必要な場合は、自分に合わせてください。ただし、これら 2 つの問題に注意してください。

コーディングを楽しんでください!

編集:そこで、ランダムな整数ジェネレーターが必要だったので、それを「正しく」コーディングすることにしました。したがって、完全な機能が必要な場合は、実際に機能するものを次に示します。(しかし、たった 2 行のコードでは最も単純な賞を獲得することはできません。しかし、実際にはそれほど複雑ではありません。)

''' <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
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

マイクロソフトの例 Rnd関数

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))

素晴らしい答えである Joseph の答えを使用している場合、これらを次のように連続して実行します。

dim i = GetRandom(1, 1715)
dim o = GetRandom(1, 1715)

その後、呼び出しが非常に迅速に処理されるため、同じ結果が何度も返される可能性があります。これは 2008 年には問題ではなかったかもしれませんが、現在ではプロセッサがはるかに高速になっているため、この関数では 2 回目の呼び出しを行う前にシステム クロックを変更するのに十分な時間がありません。

System.Random() 関数はシステム クロックに基づいているため、次の呼び出しまでにシステム クロックが変更されるのに十分な時間を確保する必要があります。これを実現する 1 つの方法は、現在のスレッドを 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

疑似乱数ジェネレータは 1 回だけ作成する必要があります。

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

好きなだけ。ラッパー関数の使用が正当化されるのは、最大値が排他的であるという理由だけです。乱数がこのように機能することはわかっていますが、.Next の定義がわかりにくいです。

私の考えでは、数字が必要になるたびにジェネレーターを作成するのは間違っています。擬似乱数はこのようには機能しません。

まず、他の返信で説明されている初期化に関する問題が発生します。一度初期化すればこの問題は発生しません。

第二に、有効な乱数列が得られるかどうかはまったくわかりません。むしろ、コンピューター時間に基づいて自動的にシードされる、複数の異なるシーケンスの最初の数のコレクションを取得します。これらの数値がシーケンスのランダム性を確認するテストに合格するかどうかはわかりません。

Dim rnd As Random = New Random
rnd.Next(n)

参考までに、RND と RANDOMIZE の VB NET Fuction 定義 (BASIC (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
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

[BBOYSE】。] これが最善の方法だ。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top