VB.NET의 임의 정수
단위 테스트에 사용할 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
클래스 생성자 가 시스템 시계를 기반으로 기본 시드를 제공 하기 때문입니다 . 대부분의 시스템에서 이는 20ms 부근의 제한된 세분성을 갖습니다. 따라서 다음 코드를 작성하면 동일한 번호를 연속으로 여러 번 얻을 수 있습니다.
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
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)
지금까지의 모든 답변에는 문제 나 버그가 있습니다 (하나가 아닌 복수). 설명을하겠습니다. 그러나 먼저 저는 Generator 변수를 기억하기 위해 정적 변수를 사용하는 Dan Tao의 통찰력을 칭찬하고 싶습니다. 그래서 여러 번 호출하면 동일한 #이 반복되지 않고 아주 좋은 설명을했습니다. 그러나 그의 코드는 내가 지금 설명하는 것처럼 다른 대부분의 코드와 동일한 결함을 가지고 있습니다.
MS는 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
(나는 int가 얼마나 큰지 더 명확하게 Int32
하기보다 사용 하는 것을 좋아하고 Integer
, 입력하는 것이 더 짧지 만 자신에게 적합합니다.)
이 방법에는 두 가지 잠재적 인 문제가 있지만 대부분의 용도에 적합하고 정확합니다. 따라서 간단한 해결책 을 원한다면 이것이 맞다고 생각합니다.
이 함수에서 볼 수있는 유일한 두 가지 문제는 1 : Max = Int32.MaxValue 일 때 1을 더하면 숫자 오버플로가 발생합니다. 알토, 이것은 드문 일이지만 여전히 가능성이 있습니다. 2 : min> max + 1. 일 때 min = 10이고 max = 5이면 Next 함수는 오류를 던집니다. 이것은 당신이 원하는 것일 수 있습니다. 그러나 둘 다 아닐 수도 있습니다. 또는 1을 추가하여 min = 5 및 max = 4. 일 때 고려하십시오 .Next 메서드에 5가 전달되지만 실제로 오류 인 경우 오류가 발생하지 않지만 테스트 한 Microsoft .NET 코드는 5를 반환하므로 최대 = 최소 일 때 실제로 '배타적'최대가 아닙니다. 그러나 Random.Next () 함수에 대해 max <min이면 ArgumentOutOfRangeException이 발생합니다. 따라서 Microsoft의 구현은 이와 관련하여 매우 일관성이없고 버그가 많습니다.
오류가 발생하지 않도록 min> max 일 때 단순히 숫자를 바꾸고 싶을 수 있지만, 원하는 것에 전적으로 의존합니다. 잘못된 값에 대한 오류를 원하는 경우 코드에서 Microsoft의 배타적 최대 값 (최대 + 1)이 최소값과 같을 때 오류를 던지는 것이 좋습니다. 여기서 MS는이 경우 오류가 발생하지 않습니다.
max = Int32.MaxValue에 대한 해결 방법을 처리하는 것이 약간 불편하지만 이러한 두 상황을 모두 처리하는 철저한 함수를 게시 할 예정입니다. 내가 코딩 한 방식과 다른 행동을 원한다면 자신에게 적합합니다. 하지만이 두 가지 문제를 알고 있어야합니다.
즐거운 코딩 되세요!
편집 : 그래서 나는 임의의 정수 생성기가 필요했고 그것을 '올바르게'코딩하기로 결정했습니다. 따라서 누구나 전체 기능을 원하는 경우 실제로 작동하는 기능이 있습니다. (하지만 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
Microsoft 예제 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)
그러면 호출을 너무 빨리 처리하기 때문에 결과가 계속해서 동일하게 돌아올 수 있습니다. 이것은 '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
의사 난수 생성기는 한 번만 생성해야합니다.
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
Random 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] 처음부터이게 최선의 방법입니다 : P
ReferenceURL : https://stackoverflow.com/questions/18676/random-integer-in-vb-net
'development' 카테고리의 다른 글
C / C ++의 무한 루프 (0) | 2020.12.26 |
---|---|
Graphics.DrawString ()의 중앙 텍스트 출력 (0) | 2020.12.26 |
경고 C4003 및 오류 C2589 및 C2059 on : x = std :: numeric_limits (0) | 2020.12.26 |
HashMap에서 검색된 값의 순서가 삽입 순서입니다. (0) | 2020.12.26 |
동적 조건이있는 Rails has_many (0) | 2020.12.26 |