Frage

Ich muss eine zufällige Ganzzahl zwischen 1 und n generieren (wobei n eine positive ganze Zahl ist), um sie für einen Komponententest zu verwenden.Ich brauche nichts allzu Kompliziertes, um echte Zufälligkeit zu gewährleisten – nur eine altmodische Zufallszahl.

Wie würde ich das machen?

War es hilfreich?

Lösung

Um einen zufälligen ganzzahligen Wert zwischen 1 und N (einschließlich) zu erhalten, können Sie Folgendes verwenden.

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

Andere Tipps

Wie schon oft darauf hingewiesen wurde, ist der Vorschlag, Code wie diesen 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 Die Klasse stellt einen Standard-Seed bereit, der auf der Systemuhr basiert.Auf 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 mehrmals hintereinander dieselbe Zahl:

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

Ich habe ein einfaches Programm zusammengestellt, das beide Methoden verwendet, um 25 zufällige ganze Zahlen zwischen 1 und 100 zu generieren.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 System.Zufällig:

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 bisherigen Antworten weisen Probleme oder Fehler auf (Plural, nicht nur eine).Ich werde erklären.Aber zuerst möchte ich Dan Taos Einsicht loben, eine statische Variable zu verwenden, um sich die Generator-Variable zu merken, sodass ein mehrmaliges Aufrufen nicht immer wieder dasselbe # wiederholt, und er hat eine sehr schöne Erklärung gegeben.Aber sein Code hatte den gleichen Fehler wie die meisten anderen, wie ich jetzt erkläre.

MS hat ihre Next()-Methode ziemlich seltsam gemacht.Der Min-Parameter ist das inklusive Minimum, wie man es erwarten würde, aber der Max-Parameter ist das exklusiv maximal, wie man es NICHT erwarten würde.Mit anderen Worten: Wenn Sie min=1 und max=5 übergeben, wären Ihre Zufallszahlen 1, 2, 3 oder 4, aber niemals 5.Dies ist der erste von zwei potenziellen Fehlern im gesamten Code, der die Random.Next()-Methode von Microsoft verwendet.

Für ein einfach Antwort (aber immer noch mit anderen möglichen, aber seltenen Problemen), dann müssten Sie Folgendes 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 benutze gerne Int32 statt Integer weil es klarer macht, wie groß das int ist, außerdem ist es kürzer in der Eingabe, passt aber zu Ihnen.)

Ich sehe zwei potenzielle Probleme bei dieser Methode, aber sie wird für die meisten Anwendungen geeignet (und richtig) sein.Also, wenn Sie ein wollen einfach Lösung, ich glaube, das ist richtig.

Die einzigen zwei Probleme, die ich bei dieser Funktion sehe, sind:1:Wenn Max = Int32.MaxValue ist, führt das Hinzufügen von 1 zu einem numerischen Überlauf.Obwohl dies selten vorkäme, ist es dennoch eine Möglichkeit.2:wenn min > max + 1.wenn min = 10 und max = 5, dann gibt die Next-Funktion einen Fehler aus.Das könnte das sein, was Sie wollen.aber vielleicht ist es das auch nicht.oder überlegen Sie, wann min = 5 und max = 4.Durch Hinzufügen von 1 wird 5 an die Next-Methode übergeben, aber es wird kein Fehler ausgegeben, obwohl es sich wirklich um einen Fehler handelt, aber der von mir getestete Microsoft .NET-Code gibt 5 zurück.Es handelt sich also wirklich nicht um ein „exklusives“ Maximum, wenn das Maximum = das Minimum ist.aber wenn max < min für die Funktion Random.Next(), dann wird eine ArgumentOutOfRangeException ausgelöst.Daher ist die Implementierung von Microsoft in dieser Hinsicht wirklich inkonsistent und fehlerhaft.

Möglicherweise möchten Sie die Zahlen einfach vertauschen, wenn min > max, damit kein Fehler ausgegeben wird. Dies hängt jedoch ganz davon ab, was gewünscht wird.Wenn Sie einen Fehler bei ungültigen Werten wünschen, ist es wahrscheinlich besser, den Fehler auch dann auszulösen, wenn das exklusive Maximum von Microsoft (max + 1) in unserem Code dem Minimum entspricht, wobei MS in diesem Fall keinen Fehler ausgibt.

Die Handhabung einer Problemumgehung für den Fall max = Int32.MaxValue ist etwas umständlich, aber ich erwarte, eine gründliche Funktion zu veröffentlichen, die diese beiden Situationen behandelt.Und wenn Sie ein anderes Verhalten wünschen, als ich es codiert habe, passen Sie es an.Aber seien Sie sich dieser beiden Probleme bewusst.

Viel Spaß beim Codieren!

Bearbeiten:Also brauchte ich einen Zufallsgenerator für ganze Zahlen und beschloss, ihn „richtig“ zu codieren.Wenn also jemand die volle Funktionalität möchte, finden Sie hier eine, die tatsächlich funktioniert.(Aber es gewinnt nicht den einfachsten Preis mit nur 2 Codezeilen.Aber es ist auch nicht wirklich komplex.)

''' <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-Beispiel Rnd-Funktion

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

1- Initialisieren Sie den Zufallszahlengenerator.

Randomize()

2 – Zufallswert zwischen 1 und 6 generieren.

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

Wenn Sie Josephs Antwort verwenden, die eine großartige Antwort ist, und diese wie folgt hintereinander ausführen:

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

Dann könnte das Ergebnis immer wieder dasselbe sein, weil der Anruf so schnell verarbeitet wird.Dies war im Jahr 2008 möglicherweise kein Problem, aber da die Prozessoren heute viel schneller sind, lässt die Funktion der Systemuhr nicht genügend Zeit, sich vor dem zweiten Aufruf zu ändern.

Da die System.Random()-Funktion auf der Systemuhr basiert, müssen wir vor dem nächsten Aufruf genügend Zeit einplanen, damit sie sich ändert.Eine Möglichkeit, dies zu erreichen, besteht darin, den aktuellen Thread für eine 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 erstellen:

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

Wenn eine Ganzzahl für Ihre Anforderungen 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 Sie möchten.Die Verwendung der Wrapper-Funktion ist nur deshalb gerechtfertigt, weil der Maximalwert exklusiv ist. Ich weiß, dass die Zufallszahlen auf diese Weise funktionieren, aber die Definition von .Next ist verwirrend.

Meiner Meinung nach ist es falsch, jedes Mal einen Generator zu erstellen, wenn Sie eine Nummer benötigen.Die Pseudozufallszahlen funktionieren auf diese Weise nicht.

Erstens tritt das Problem mit der Initialisierung auf, das in den anderen Antworten besprochen wurde.Wenn Sie einmal initialisieren, tritt dieses Problem nicht auf.

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

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

Nur als Referenz lautet die VB NET-Funktionsdefinition für RND und RANDOMIZE (die die gleichen Ergebnisse von BASIC (1980 Jahre) und allen Versionen danach liefern sollte):

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 Zufallsklasse lautet:

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top