Zufällige Ganzzahl in VB.NET

Ich muss eine zufällige Ganzzahl zwischen 1 und n erzeugen (wobei n eine positive ganze Zahl ist), um sie für einen Einheitentest zu verwenden. Ich brauche nichts übermäßig kompliziert, um wahre Zufälligkeit zu gewährleisten – nur eine altmodische Zufallszahl.

Wie würde ich das tun?

Um einen zufälligen Ganzzahlwert zwischen 1 und N (inklusive) zu erhalten, können Sie Folgendes verwenden.

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

Wie schon oft betont wurde, ist der Vorschlag, solchen Code zu schreiben, problematisch:

 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 

Der Grund dafür ist, dass der Konstruktor für die Random class einen Standard-Seed basierend auf der Systemuhr bereitstellt. Bei den meisten Systemen hat dies eine begrenzte Granularität – irgendwo in der Nähe von 20 ms. Wenn Sie also den folgenden Code schreiben, erhalten Sie die gleiche Nummer mehrmals hintereinander:

 Dim randoms(1000) As Integer For i As Integer = 0 to randoms.Length - 1 randoms(i) = GetRandom(1, 100) Next 

Der folgende Code behebt dieses Problem:

 Public Function GetRandom(ByVal Min As Integer, ByVal Max As Integer) As Integer ' by making Generator static, we preserve the same instance ' ' (ie, 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 

Ich habe ein einfaches Programm mit beiden Methoden zusammengestellt, um 25 zufällige Ganzzahlen zwischen 1 und 100 zu erzeugen. Hier ist die Ausgabe:

 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 

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

Alle Antworten haben bisher Probleme oder Bugs (Plural, nicht nur eins). Ich werde erklären. Aber zuerst möchte ich Dan Taos Einsicht gratulieren, dass er eine statische Variable verwendet, um sich an die Variable Generator zu erinnern, so dass sie mehrmals hintereinander nicht wiederholt wird und dass er eine sehr schöne Erklärung gegeben hat. Aber sein Code hatte denselben Fehler wie die meisten anderen, wie ich jetzt erkläre.

MS machte ihre Next () -Methode eher seltsam. Der Min-Parameter ist das Inklusiv-Minimum, wie man erwarten würde, aber der Max-Parameter ist das exklusive Maximum, wie man es NICHT erwarten würde. Mit anderen Worten, wenn Sie min = 1 und max = 5 übergeben, dann sind Ihre Zufallszahlen 1, 2, 3 oder 4, aber es würde niemals 5 enthalten. Dies ist der erste von zwei möglichen Fehlern im gesamten Code verwendet die Random.Next () -Methode von Microsoft.

Für eine einfache Antwort (aber immer noch mit anderen möglichen aber seltenen Problemen) müssten Sie dann verwenden:

 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 

(Ich Int32 lieber Int32 als Integer weil es deutlicher macht, wie groß der Int ist, außerdem ist es kürzer zu tippen, aber passt zu dir selbst.)

Ich sehe zwei mögliche Probleme mit dieser Methode, aber es wird für die meisten Anwendungen geeignet (und korrekt) sein. Also, wenn Sie eine einfache Lösung wollen, ich glaube, das ist richtig.

Die einzige 2 Probleme, die ich mit dieser function sehe, ist: 1: wenn Max = Int32.MaxValue, so dass 1 einen numerischen Überlauf erstellt. Das wäre selten, es ist immer noch möglich. 2: wenn min> max + 1. wenn min = 10 und max = 5 dann gibt die function Next einen Fehler aus. das könnte sein, was du willst. aber es kann auch nicht sein. oder überlegen, wenn min = 5 und max = 4. durch Hinzufügen von 1, 5 wird an die nächste Methode übergeben, aber es wirft keinen Fehler, wenn es wirklich ein Fehler ist, aber Microsoft .NET-Code, den ich getestet habe, gibt 5. so Es ist wirklich kein “exklusives” Maximum, wenn das Maximum = das Minimum ist. Wenn jedoch max

Sie können die Zahlen einfach austauschen, wenn min> max, so dass kein Fehler ausgetriggers wird, aber es hängt ganz davon ab, was gewünscht wird. Wenn Sie einen Fehler bei ungültigen Werten wünschen, dann ist es wahrscheinlich besser, den Fehler auch zu casting, wenn Microsofts exklusives Maximum (max + 1) in unserem Code gleich Minimum ist, wobei MS in diesem Fall auf Fehler versagt.

Einen work-around zu behandeln, wenn max = Int32.MaxValue ist ein wenig unbequem, aber ich erwarte, eine gründliche function zu veröffentlichen, die diese beiden Situationen behandelt. und wenn du ein anderes Verhalten willst, als wie ich es kodiere, dann pass auf dich auf. Aber seien Sie sich dieser zwei Punkte bewusst.

Glückliche Kodierung!

Edit: Also brauchte ich einen zufälligen Integer-Generator, und ich beschloss, es richtig zu kodieren. Also, wenn jemand die volle functionalität will, hier ist eine, die tatsächlich funktioniert. (Aber es gewinnt nicht den einfachsten Preis mit nur 2 Zeilen Code. Aber es ist auch nicht wirklich komplex.)

 '''  ''' Generates a random Integer with any (inclusive) minimum or (inclusive) maximum values, with full range of Int32 values. '''  ''' Inclusive Minimum value. Lowest possible return value. ''' Inclusive Maximum value. Highest possible return value. '''  '''  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 Beispiel Rnd-function

https://msdn.microsoft.com/en-us/library/f7s023d2%28v=vs.90%29.aspx

1- Initialisieren Sie den Zufallszahlengenerator.

 Randomize() 

2 – Erzeuge Zufallswert zwischen 1 und 6.

 Dim value As Integer = CInt(Int((6 * Rnd()) + 1)) 

Wenn du Josephs Antwort verwendest, die eine großartige Antwort ist, und du rennst diese Rücken an Rücken so:

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

Dann könnte das Ergebnis immer wieder dasselbe kommen, weil es den Anruf so schnell verarbeitet. Dies mag in ’08 kein Problem gewesen sein, aber da die processoren heute viel schneller sind, erlaubt die function der Systemuhr nicht genug Zeit, um sich vor dem zweiten Aufruf zu ändern.

Da die System.Random () – function auf der Systemuhr basiert, müssen wir genügend Zeit für das Ändern von es vor dem nächsten Aufruf zulassen. Eine Möglichkeit, dies zu erreichen, besteht darin, den aktuellen Thread für 1 Millisekunde anzuhalten. Siehe Beispiel unten:

 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 

Sie sollten einen Pseudozufallszahlengenerator nur einmal anlegen:

 Dim Generator As System.Random = New System.Random() 

Wenn eine ganze Zahl für Ihre Bedürfnisse ausreicht, können Sie Folgendes verwenden:

 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 

so oft du willst. Die Verwendung der Wrapper-function ist nur gerechtfertigt, weil der Maximalwert exklusiv ist – ich weiß, dass die Zufallszahlen auf diese Weise funktionieren, aber die Definition von .Next ist verwirrend.

Einen Generator immer dann zu erstellen, wenn man eine Nummer braucht, ist meiner Meinung nach falsch; Die Pseudozufallszahlen funktionieren nicht auf diese Weise.

Zuerst erhalten Sie das Problem mit der Initialisierung, die in den anderen Antworten besprochen wurde. Wenn Sie einmal initialisiert haben, haben Sie dieses Problem nicht.

Zweitens bin ich überhaupt nicht sicher, dass Sie eine gültige Folge von Zufallszahlen erhalten; Stattdessen erhalten Sie eine Sammlung der ersten Anzahl mehrerer verschiedener Sequenzen, die automatisch basierend auf der Computerzeit gesetzt werden. Ich bin nicht sicher, dass diese Zahlen die Tests bestehen werden, die die Zufälligkeit der Sequenz bestätigen.

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

Nur als Referenz, VB NET Fuction Definition für RND und RANDOMIZE (die die gleichen Ergebnisse von BASIC (1980 Jahre) und alle Versionen danach geben soll ist:

 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 

Während die zufällige class ist:

 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] Das ist der beste Weg, von Grund auf: P