System.Random-Klasse

Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.

Die Random Klasse stellt einen Pseudo-Zufallszahlengenerator dar, bei dem es sich um einen Algorithmus handelt, der eine Folge von Zahlen erzeugt, die bestimmte statistische Anforderungen an Zufallsvarianz erfüllen.

Pseudo-Zufallszahlen werden mit gleicher Wahrscheinlichkeit aus einer endlichen Gruppe von Zahlen ausgewählt. Die gewählten Zahlen sind nicht vollständig zufällig, da ein mathematischer Algorithmus verwendet wird, um sie auszuwählen, aber sie sind für praktische Zwecke ausreichend zufällig. Die Implementierung der Random Klasse basiert auf einer modifizierten Version von Donald E. Knuths subtrahierendem Zufallszahlengeneratoralgorithmus. Weitere Informationen finden Sie unter D. E. Knuth. Die Kunst der Computerprogrammierung, Volume 2: Seminumerische Algorithmen. Addison-Wesley, Reading, MA, dritte Ausgabe, 1997.

Um eine kryptografisch sichere Zufallszahl zu generieren, z. B. eine, die zum Erstellen eines zufälligen Kennworts geeignet ist, verwenden Sie die RNGCryptoServiceProvider Klasse, oder leiten Sie eine Klasse von System.Security.Cryptography.RandomNumberGenerator.

Instanziieren des Zufallszahlengenerators

Sie instanziieren den Zufallszahlengenerator, indem Sie einen Ausgangswert (einen Startwert für den Pseudo-Zufallszahlengenerierungsalgorithmus) für einen Random Klassenkonstruktor angeben. Sie können den Seedwert entweder explizit oder implizit angeben:

  • Der Random(Int32) Konstruktor verwendet einen expliziten Seedwert, den Sie angeben.
  • Der Random() Konstruktor verwendet den Standardsamenwert. Dies ist die am häufigsten verwendete Methode zum Instanziieren des Zufallszahlengenerators.

In .NET Framework ist der Standardwert zeitabhängig. In .NET Core wird der Standardsamenwert vom Thread-statischen Pseudo-Zufallszahlengenerator erzeugt.

Wenn derselbe Ausgangswert für separate Random Objekte verwendet wird, generieren sie dieselbe Reihe von Zufallszahlen. Dies kann hilfreich sein, um eine Testsuite zu erstellen, die Zufallswerte verarbeitet, oder zum Wiedergeben von Spielen, die ihre Daten aus Zufallszahlen ableiten. Beachten Sie jedoch, dass Random Objekte in Prozessen, die unter verschiedenen Versionen von .NET Framework ausgeführt werden, möglicherweise unterschiedliche Zufallszahlen zurückgeben, auch wenn sie mit identischen Seedwerten instanziiert werden.

Um unterschiedliche Sequenzen von Zufallszahlen zu erzeugen, können Sie den Ausgangswert zeitabhängig machen und so eine andere Datenreihe mit jeder neuen Instanz von Random. Der parametrisierte Random(Int32) Konstruktor kann basierend auf der Anzahl der Teilstriche in der aktuellen Zeit einen Int32 Wert annehmen, während der parameterlose Random() Konstruktor die Systemuhr verwendet, um seinen Ausgangswert zu generieren. In .NET Framework jedoch nur, da die Uhr eine endliche Auflösung aufweist, erstellt der parameterlose Konstruktor zum Erstellen verschiedener Random Objekte in enger Folge Zufallszahlengeneratoren, die identische Sequenzen von Zufallszahlen erzeugen. Im folgenden Beispiel wird veranschaulicht, wie zwei Random Objekte, die in einer .NET Framework-Anwendung in enger Folge instanziiert werden, eine identische Reihe von Zufallszahlen generieren. Auf den meisten Windows-Systemen werden Objekte, die innerhalb von 15 Millisekunden erstellt wurden, Random wahrscheinlich identische Ausgangswerte aufweisen.

byte[] bytes1 = new byte[100];
byte[] bytes2 = new byte[100];
Random rnd1 = new Random();
Random rnd2 = new Random();

rnd1.NextBytes(bytes1);
rnd2.NextBytes(bytes2);

Console.WriteLine("First Series:");
for (int ctr = bytes1.GetLowerBound(0);
     ctr <= bytes1.GetUpperBound(0);
     ctr++) {
   Console.Write("{0, 5}", bytes1[ctr]);
   if ((ctr + 1) % 10 == 0) Console.WriteLine();
}

Console.WriteLine();

Console.WriteLine("Second Series:");
for (int ctr = bytes2.GetLowerBound(0);
     ctr <= bytes2.GetUpperBound(0);
     ctr++) {
   Console.Write("{0, 5}", bytes2[ctr]);
   if ((ctr + 1) % 10 == 0) Console.WriteLine();
}

// The example displays output like the following:
//       First Series:
//          97  129  149   54   22  208  120  105   68  177
//         113  214   30  172   74  218  116  230   89   18
//          12  112  130  105  116  180  190  200  187  120
//           7  198  233  158   58   51   50  170   98   23
//          21    1  113   74  146  245   34  255   96   24
//         232  255   23    9  167  240  255   44  194   98
//          18  175  173  204  169  171  236  127  114   23
//         167  202  132   65  253   11  254   56  214  127
//         145  191  104  163  143    7  174  224  247   73
//          52    6  231  255    5  101   83  165  160  231
//
//       Second Series:
//          97  129  149   54   22  208  120  105   68  177
//         113  214   30  172   74  218  116  230   89   18
//          12  112  130  105  116  180  190  200  187  120
//           7  198  233  158   58   51   50  170   98   23
//          21    1  113   74  146  245   34  255   96   24
//         232  255   23    9  167  240  255   44  194   98
//          18  175  173  204  169  171  236  127  114   23
//         167  202  132   65  253   11  254   56  214  127
//         145  191  104  163  143    7  174  224  247   73
//          52    6  231  255    5  101   83  165  160  231
let bytes1 = Array.zeroCreate 100
let bytes2 = Array.zeroCreate 100
let rnd1 = Random()
let rnd2 = Random()

rnd1.NextBytes bytes1 
rnd2.NextBytes bytes2 

printfn "First Series"
for i = bytes1.GetLowerBound 0 to bytes1.GetUpperBound 0 do
    printf "%5i" bytes1.[i]
    if (i + 1) % 10 = 0 then printfn ""

printfn ""

printfn "Second Series"
for i = bytes2.GetLowerBound 0 to bytes2.GetUpperBound 0 do
    printf "%5i" bytes2.[i]
    if (i + 1) % 10 = 0 then printfn ""

// The example displays output like the following:
//       First Series:
//          97  129  149   54   22  208  120  105   68  177
//         113  214   30  172   74  218  116  230   89   18
//          12  112  130  105  116  180  190  200  187  120
//           7  198  233  158   58   51   50  170   98   23
//          21    1  113   74  146  245   34  255   96   24
//         232  255   23    9  167  240  255   44  194   98
//          18  175  173  204  169  171  236  127  114   23
//         167  202  132   65  253   11  254   56  214  127
//         145  191  104  163  143    7  174  224  247   73
//          52    6  231  255    5  101   83  165  160  231
//
//       Second Series:
//          97  129  149   54   22  208  120  105   68  177
//         113  214   30  172   74  218  116  230   89   18
//          12  112  130  105  116  180  190  200  187  120
//           7  198  233  158   58   51   50  170   98   23
//          21    1  113   74  146  245   34  255   96   24
//         232  255   23    9  167  240  255   44  194   98
//          18  175  173  204  169  171  236  127  114   23
//         167  202  132   65  253   11  254   56  214  127
//         145  191  104  163  143    7  174  224  247   73
//          52    6  231  255    5  101   83  165  160  231
Module modMain

   Public Sub Main()
      Dim bytes1(99), bytes2(99) As Byte
      Dim rnd1 As New Random()
      Dim rnd2 As New Random()
      
      rnd1.NextBytes(bytes1)
      rnd2.NextBytes(bytes2)
      
      Console.WriteLine("First Series:")
      For ctr As Integer = bytes1.GetLowerBound(0) to bytes1.GetUpperBound(0)
         Console.Write("{0, 5}", bytes1(ctr))
         If (ctr + 1) Mod 10 = 0 Then Console.WriteLine()
      Next 
      Console.WriteLine()
      Console.WriteLine("Second Series:")        
      For ctr As Integer = bytes2.GetLowerBound(0) to bytes2.GetUpperBound(0)
         Console.Write("{0, 5}", bytes2(ctr))
         If (ctr + 1) Mod 10 = 0 Then Console.WriteLine()
      Next   
   End Sub
End Module
' The example displays output like the following:
'       First Series:
'          97  129  149   54   22  208  120  105   68  177
'         113  214   30  172   74  218  116  230   89   18
'          12  112  130  105  116  180  190  200  187  120
'           7  198  233  158   58   51   50  170   98   23
'          21    1  113   74  146  245   34  255   96   24
'         232  255   23    9  167  240  255   44  194   98
'          18  175  173  204  169  171  236  127  114   23
'         167  202  132   65  253   11  254   56  214  127
'         145  191  104  163  143    7  174  224  247   73
'          52    6  231  255    5  101   83  165  160  231
'       
'       Second Series:
'          97  129  149   54   22  208  120  105   68  177
'         113  214   30  172   74  218  116  230   89   18
'          12  112  130  105  116  180  190  200  187  120
'           7  198  233  158   58   51   50  170   98   23
'          21    1  113   74  146  245   34  255   96   24
'         232  255   23    9  167  240  255   44  194   98
'          18  175  173  204  169  171  236  127  114   23
'         167  202  132   65  253   11  254   56  214  127
'         145  191  104  163  143    7  174  224  247   73
'          52    6  231  255    5  101   83  165  160  231

Um dieses Problem zu vermeiden, erstellen Sie ein einzelnes Random Objekt anstelle mehrerer Objekte. Beachten Sie, dass die Random Klasse in .NET Core diese Einschränkung nicht hat.

Vermeiden mehrerer Instanziierungen

In .NET Framework erstellt das Initialisieren von zwei Zufallszahlengeneratoren in einer engen Schleife oder in schneller Folge zwei Zufallszahlengeneratoren, die identische Sequenzen von Zufallszahlen erzeugen können. In den meisten Fällen ist dies nicht die Absicht des Entwicklers und kann zu Leistungsproblemen führen, da das Instanziieren und Initialisieren eines Zufallszahlengenerators ein relativ kostspieliger Prozess ist.

Sowohl zur Verbesserung der Leistung als auch zur Vermeidung versehentlicher Erstellung separater Zufallszahlengeneratoren, die identische numerische Sequenzen generieren, wird empfohlen, ein Random Objekt zu erstellen, um im Laufe der Zeit viele Zufallszahlen zu generieren, anstatt neue Random Objekte zu erstellen, um eine Zufallszahl zu generieren.

Die Random Klasse ist jedoch nicht threadsicher. Wenn Sie Methoden aus mehreren Threads aufrufen Random , befolgen Sie die im nächsten Abschnitt beschriebenen Richtlinien.

Threadsicherheit

Anstatt einzelne Random Objekte zu instanziieren, empfiehlt es sich, eine einzelne Random Instanz zu erstellen, um alle Zufallszahlen zu generieren, die von Ihrer App benötigt werden. Random Objekte sind jedoch nicht threadsicher. Wenn Ihre App Methoden aus mehreren Threads aufruft Random , müssen Sie ein Synchronisierungsobjekt verwenden, um sicherzustellen, dass jeweils nur ein Thread auf den Zufallszahlengenerator zugreifen kann. Wenn Sie nicht sicherstellen, dass auf das Random Objekt auf threadsichere Weise zugegriffen wird, geben Aufrufe von Methoden, die Zufallszahlen zurückgeben, "0" zurück.

Im folgenden Beispiel wird die C# -Lock-Anweisung, die F# -Sperrfunktion und die Visual Basic SyncLock-Anweisung verwendet, um sicherzustellen, dass ein einzelner Zufallszahlengenerator von 11 Threads auf threadsichere Weise zugegriffen wird. Jeder Thread generiert 2 Millionen Zufallszahlen, zählt die Anzahl der generierten Zufallszahlen und berechnet ihre Summe und aktualisiert dann die Summen für alle Threads, wenn sie die Ausführung abgeschlossen hat.

using System;
using System.Threading;

public class Example13
{
    [ThreadStatic] static double previous = 0.0;
    [ThreadStatic] static int perThreadCtr = 0;
    [ThreadStatic] static double perThreadTotal = 0.0;
    static CancellationTokenSource source;
    static CountdownEvent countdown;
    static Object randLock, numericLock;
    static Random rand;
    double totalValue = 0.0;
    int totalCount = 0;

    public Example13()
    {
        rand = new Random();
        randLock = new Object();
        numericLock = new Object();
        countdown = new CountdownEvent(1);
        source = new CancellationTokenSource();
    }

    public static void Main()
    {
        Example13 ex = new Example13();
        Thread.CurrentThread.Name = "Main";
        ex.Execute();
    }

    private void Execute()
    {
        CancellationToken token = source.Token;

        for (int threads = 1; threads <= 10; threads++)
        {
            Thread newThread = new Thread(this.GetRandomNumbers);
            newThread.Name = threads.ToString();
            newThread.Start(token);
        }
        this.GetRandomNumbers(token);

        countdown.Signal();
        // Make sure all threads have finished.
        countdown.Wait();
        source.Dispose();

        Console.WriteLine("\nTotal random numbers generated: {0:N0}", totalCount);
        Console.WriteLine("Total sum of all random numbers: {0:N2}", totalValue);
        Console.WriteLine("Random number mean: {0:N4}", totalValue / totalCount);
    }

    private void GetRandomNumbers(Object o)
    {
        CancellationToken token = (CancellationToken)o;
        double result = 0.0;
        countdown.AddCount(1);

        try
        {
            for (int ctr = 0; ctr < 2000000; ctr++)
            {
                // Make sure there's no corruption of Random.
                token.ThrowIfCancellationRequested();

                lock (randLock)
                {
                    result = rand.NextDouble();
                }
                // Check for corruption of Random instance.
                if ((result == previous) && result == 0)
                {
                    source.Cancel();
                }
                else
                {
                    previous = result;
                }
                perThreadCtr++;
                perThreadTotal += result;
            }

            Console.WriteLine("Thread {0} finished execution.",
                              Thread.CurrentThread.Name);
            Console.WriteLine("Random numbers generated: {0:N0}", perThreadCtr);
            Console.WriteLine("Sum of random numbers: {0:N2}", perThreadTotal);
            Console.WriteLine("Random number mean: {0:N4}\n", perThreadTotal / perThreadCtr);

            // Update overall totals.
            lock (numericLock)
            {
                totalCount += perThreadCtr;
                totalValue += perThreadTotal;
            }
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine("Corruption in Thread {1}", e.GetType().Name, Thread.CurrentThread.Name);
        }
        finally
        {
            countdown.Signal();
        }
    }
}
// The example displays output like the following:
//       Thread 6 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,491.05
//       Random number mean: 0.5002
//
//       Thread 10 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,329.64
//       Random number mean: 0.4997
//
//       Thread 4 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,166.89
//       Random number mean: 0.5001
//
//       Thread 8 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,628.37
//       Random number mean: 0.4998
//
//       Thread Main finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,920.89
//       Random number mean: 0.5000
//
//       Thread 3 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,370.45
//       Random number mean: 0.4997
//
//       Thread 7 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,330.92
//       Random number mean: 0.4997
//
//       Thread 9 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,172.79
//       Random number mean: 0.5001
//
//       Thread 5 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,079.43
//       Random number mean: 0.5000
//
//       Thread 1 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,817.91
//       Random number mean: 0.4999
//
//       Thread 2 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,930.63
//       Random number mean: 0.5000
//
//
//       Total random numbers generated: 22,000,000
//       Total sum of all random numbers: 10,998,238.98
//       Random number mean: 0.4999
open System
open System.Threading

type Example() =
    [<ThreadStatic; DefaultValue>]
    static val mutable private previous : float
    
    [<ThreadStatic; DefaultValue>]
    static val mutable private perThreadCtr : int

    [<ThreadStatic; DefaultValue>]
    static val mutable private perThreadTotal : float

    static let source = new CancellationTokenSource()
    static let countdown = new CountdownEvent(1)
    static let randLock = obj ()
    static let numericLock = obj ()
    static let rand = Random()

    let mutable totalValue = 0.0
    let mutable totalCount = 0

    member _.GetRandomNumbers(token: CancellationToken) =
        let mutable result = 0.0
        countdown.AddCount 1
        try 
            try
                for _ = 0 to 1999999 do
                    // Make sure there's no corruption of Random.
                    token.ThrowIfCancellationRequested()

                    lock randLock (fun () -> 
                        result <- rand.NextDouble() )

                    // Check for corruption of Random instance.
                    if result = Example.previous && result = 0.0 then 
                        source.Cancel()
                    else
                        Example.previous <- result
                        
                    Example.perThreadCtr <- Example.perThreadCtr + 1
                    Example.perThreadTotal <- Example.perThreadTotal + result

                // Update overall totals.
                lock numericLock (fun () ->
                    // Show result.
                    printfn "Thread %s finished execution." Thread.CurrentThread.Name
                    printfn $"Random numbers generated: {Example.perThreadCtr:N0}" 
                    printfn $"Sum of random numbers: {Example.perThreadTotal:N2}" 
                    printfn $"Random number mean: {(Example.perThreadTotal / float Example.perThreadCtr):N4}\n"
                    
                    // Update overall totals.
                    totalCount <- totalCount + Example.perThreadCtr
                    totalValue <- totalValue + Example.perThreadTotal)

            with :? OperationCanceledException as e -> 
                printfn "Corruption in Thread %s %s" (e.GetType().Name) Thread.CurrentThread.Name
        finally
            countdown.Signal() |> ignore

    member this.Execute() =
        let token = source.Token
        for i = 1 to 10 do 
            let newThread = Thread(fun () -> this.GetRandomNumbers token)
            newThread.Name <- string i
            newThread.Start()
        this.GetRandomNumbers token
        
        countdown.Signal() |> ignore

        countdown.Wait()

        source.Dispose()

        printfn $"\nTotal random numbers generated: {totalCount:N0}"
        printfn $"Total sum of all random numbers: {totalValue:N2}"
        printfn $"Random number mean: {(totalValue / float totalCount):N4}"

let ex = Example()
Thread.CurrentThread.Name <- "Main"
ex.Execute()

// The example displays output like the following:
//       Thread 6 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,491.05
//       Random number mean: 0.5002
//
//       Thread 10 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,329.64
//       Random number mean: 0.4997
//
//       Thread 4 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,166.89
//       Random number mean: 0.5001
//
//       Thread 8 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,628.37
//       Random number mean: 0.4998
//
//       Thread Main finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,920.89
//       Random number mean: 0.5000
//
//       Thread 3 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,370.45
//       Random number mean: 0.4997
//
//       Thread 7 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,330.92
//       Random number mean: 0.4997
//
//       Thread 9 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,172.79
//       Random number mean: 0.5001
//
//       Thread 5 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,079.43
//       Random number mean: 0.5000
//
//       Thread 1 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,817.91
//       Random number mean: 0.4999
//
//       Thread 2 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,930.63
//       Random number mean: 0.5000
//
//
//       Total random numbers generated: 22,000,000
//       Total sum of all random numbers: 10,998,238.98
//       Random number mean: 0.4999
Imports System.Threading

Module Example15
    <ThreadStatic> Dim previous As Double = 0.0
    <ThreadStatic> Dim perThreadCtr As Integer = 0
    <ThreadStatic> Dim perThreadTotal As Double = 0.0
    Dim source As New CancellationTokenSource()
    Dim countdown As New CountdownEvent(1)
    Dim randLock As New Object()
    Dim numericLock As New Object()
    Dim rand As New Random()
    Dim totalValue As Double = 0.0
    Dim totalCount As Integer = 0

    Public Sub Main()
        Thread.CurrentThread.Name = "Main"

        Dim token As CancellationToken = source.Token
        For threads As Integer = 1 To 10
            Dim newThread As New Thread(AddressOf GetRandomNumbers)
            newThread.Name = threads.ToString()
            newThread.Start(token)
        Next
        GetRandomNumbers(token)

        countdown.Signal()
        ' Make sure all threads have finished.
        countdown.Wait()

        Console.WriteLine()
        Console.WriteLine("Total random numbers generated: {0:N0}", totalCount)
        Console.WriteLine("Total sum of all random numbers: {0:N2}", totalValue)
        Console.WriteLine("Random number mean: {0:N4}", totalValue / totalCount)
    End Sub

    Private Sub GetRandomNumbers(o As Object)
        Dim token As CancellationToken = CType(o, CancellationToken)
        Dim result As Double = 0.0
        countdown.AddCount(1)

        Try
            For ctr As Integer = 1 To 2000000
                ' Make sure there's no corruption of Random.
                token.ThrowIfCancellationRequested()

                SyncLock randLock
                    result = rand.NextDouble()
                End SyncLock
                ' Check for corruption of Random instance.
                If result = previous AndAlso result = 0 Then
                    source.Cancel()
                Else
                    previous = result
                End If
                perThreadCtr += 1
                perThreadTotal += result
            Next

            Console.WriteLine("Thread {0} finished execution.",
                           Thread.CurrentThread.Name)
            Console.WriteLine("Random numbers generated: {0:N0}", perThreadCtr)
            Console.WriteLine("Sum of random numbers: {0:N2}", perThreadTotal)
            Console.WriteLine("Random number mean: {0:N4}", perThreadTotal / perThreadCtr)
            Console.WriteLine()

            ' Update overall totals.
            SyncLock numericLock
                totalCount += perThreadCtr
                totalValue += perThreadTotal
            End SyncLock
        Catch e As OperationCanceledException
            Console.WriteLine("Corruption in Thread {1}", e.GetType().Name, Thread.CurrentThread.Name)
        Finally
            countdown.Signal()
            source.Dispose()
        End Try
    End Sub
End Module
' The example displays output like the following:
'       Thread 6 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,491.05
'       Random number mean: 0.5002
'       
'       Thread 10 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,329.64
'       Random number mean: 0.4997
'       
'       Thread 4 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,166.89
'       Random number mean: 0.5001
'       
'       Thread 8 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,628.37
'       Random number mean: 0.4998
'       
'       Thread Main finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,920.89
'       Random number mean: 0.5000
'       
'       Thread 3 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,370.45
'       Random number mean: 0.4997
'       
'       Thread 7 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,330.92
'       Random number mean: 0.4997
'       
'       Thread 9 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,172.79
'       Random number mean: 0.5001
'       
'       Thread 5 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,079.43
'       Random number mean: 0.5000
'       
'       Thread 1 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,817.91
'       Random number mean: 0.4999
'       
'       Thread 2 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,930.63
'       Random number mean: 0.5000
'       
'       
'       Total random numbers generated: 22,000,000
'       Total sum of all random numbers: 10,998,238.98
'       Random number mean: 0.4999

Im Beispiel wird die Threadsicherheit auf folgende Weise sichergestellt:

  • Das ThreadStaticAttribute Attribut wird verwendet, um threadlokale Variablen zu definieren, die die Gesamtanzahl der generierten Zufallszahlen und deren Summe für jeden Thread nachverfolgen.
  • Eine Sperre (die lock Anweisung in C#, die lock Funktion in F# und die SyncLock Anweisung in Visual Basic) schützt den Zugriff auf die Variablen für die Gesamtanzahl und die Summe aller Zufallszahlen, die in allen Threads generiert werden.
  • Ein Semaphor (das CountdownEvent Objekt) wird verwendet, um sicherzustellen, dass der Standard Thread blockiert wird, bis alle anderen Threads die Ausführung abschließen.
  • Im Beispiel wird überprüft, ob der Zufallszahlengenerator beschädigt wurde, indem ermittelt wird, ob zwei aufeinander folgende Aufrufe von Methoden zur Zufallszahlengenerierung 0 zurückgeben. Wenn Beschädigungen erkannt werden, wird im Beispiel das CancellationTokenSource Objekt verwendet, um zu signalisieren, dass alle Threads abgebrochen werden sollen.
  • Vor dem Generieren jeder Zufallszahl überprüft jeder Thread den Status des CancellationToken Objekts. Wenn der Abbruch angefordert wird, ruft das Beispiel die CancellationToken.ThrowIfCancellationRequested Methode auf, um den Thread abzubrechen.

Das folgende Beispiel ist identisch mit dem ersten, mit der Ausnahme, dass anstelle von Thread Objekten ein Task Objekt und ein Lambda-Ausdruck verwendet werden.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class Example15
{
    static Object randLock, numericLock;
    static Random rand;
    static CancellationTokenSource source;
    double totalValue = 0.0;
    int totalCount = 0;

    public Example15()
    {
        rand = new Random();
        randLock = new Object();
        numericLock = new Object();
        source = new CancellationTokenSource();
    }

    public static async Task Main()
    {
        Example15 ex = new Example15();
        Thread.CurrentThread.Name = "Main";
        await ex.Execute();
    }

    private async Task Execute()
    {
        List<Task> tasks = new List<Task>();

        for (int ctr = 0; ctr <= 10; ctr++)
        {
            CancellationToken token = source.Token;
            int taskNo = ctr;
            tasks.Add(Task.Run(() =>
               {
                   double previous = 0.0;
                   int taskCtr = 0;
                   double taskTotal = 0.0;
                   double result = 0.0;

                   for (int n = 0; n < 2000000; n++)
                   {
                       // Make sure there's no corruption of Random.
                       token.ThrowIfCancellationRequested();

                       lock (randLock)
                       {
                           result = rand.NextDouble();
                       }
                       // Check for corruption of Random instance.
                       if ((result == previous) && result == 0)
                       {
                           source.Cancel();
                       }
                       else
                       {
                           previous = result;
                       }
                       taskCtr++;
                       taskTotal += result;
                   }

                   // Show result.
                   Console.WriteLine("Task {0} finished execution.", taskNo);
                   Console.WriteLine("Random numbers generated: {0:N0}", taskCtr);
                   Console.WriteLine("Sum of random numbers: {0:N2}", taskTotal);
                   Console.WriteLine("Random number mean: {0:N4}\n", taskTotal / taskCtr);

                   // Update overall totals.
                   lock (numericLock)
                   {
                       totalCount += taskCtr;
                       totalValue += taskTotal;
                   }
               },
            token));
        }
        try
        {
            await Task.WhenAll(tasks.ToArray());
            Console.WriteLine("\nTotal random numbers generated: {0:N0}", totalCount);
            Console.WriteLine("Total sum of all random numbers: {0:N2}", totalValue);
            Console.WriteLine("Random number mean: {0:N4}", totalValue / totalCount);
        }
        catch (AggregateException e)
        {
            foreach (Exception inner in e.InnerExceptions)
            {
                TaskCanceledException canc = inner as TaskCanceledException;
                if (canc != null)
                    Console.WriteLine("Task #{0} cancelled.", canc.Task.Id);
                else
                    Console.WriteLine("Exception: {0}", inner.GetType().Name);
            }
        }
        finally
        {
            source.Dispose();
        }
    }
}
// The example displays output like the following:
//       Task 1 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,502.47
//       Random number mean: 0.5003
//
//       Task 0 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,445.63
//       Random number mean: 0.5002
//
//       Task 2 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,556.04
//       Random number mean: 0.5003
//
//       Task 3 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,178.87
//       Random number mean: 0.5001
//
//       Task 4 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,819.17
//       Random number mean: 0.4999
//
//       Task 5 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,190.58
//       Random number mean: 0.5001
//
//       Task 6 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,720.21
//       Random number mean: 0.4999
//
//       Task 7 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,000.96
//       Random number mean: 0.4995
//
//       Task 8 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,499.33
//       Random number mean: 0.4997
//
//       Task 9 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,193.25
//       Random number mean: 0.5001
//
//       Task 10 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,960.82
//       Random number mean: 0.5000
//
//
//       Total random numbers generated: 22,000,000
//       Total sum of all random numbers: 11,000,067.33
//       Random number mean: 0.5000
open System
open System.Threading
open System.Threading.Tasks

type Example() =
    static let source = new CancellationTokenSource()
    static let rand = Random()

    static let randLock = obj ()
    static let numericLock = obj ()

    let mutable totalValue = 0.0
    let mutable totalCount = 0

    member _.Execute() =
        use source = source // Dispose of the CancellationTokenSource when we're done with it.
        let token = source.Token

        let tasks =
            [| for i = 0 to 10 do
                   Task.Run(
                       (fun () ->
                           let mutable previous = 0.0
                           let mutable taskCtr = 0
                           let mutable taskTotal = 0.0
                           let mutable result = 0.0

                           for _ = 1 to 2000000 do
                               // Make sure there's no corruption of Random.
                               token.ThrowIfCancellationRequested()

                               lock randLock (fun () -> result <- rand.NextDouble())

                               // Check for corruption of Random instance.
                               if result = previous && result = 0.0 then
                                   source.Cancel()
                               else
                                   previous <- result

                               taskCtr <- taskCtr + 1
                               taskTotal <- taskTotal + result

                           lock numericLock (fun () ->
                               // Show result.
                               printfn "Task %i finished execution." i
                               printfn $"Random numbers generated: {taskCtr:N0}"
                               printfn $"Sum of random numbers: {taskTotal:N2}"
                               printfn $"Random number mean: {(taskTotal / float taskCtr):N4}\n"

                               // Update overall totals.
                               totalCount <- totalCount + taskCtr
                               totalValue <- totalValue + taskTotal)),
                       token
                   ) |]

        try
            // Run tasks with F# Async.
            Task.WhenAll tasks
            |> Async.AwaitTask
            |> Async.RunSynchronously

            printfn $"\nTotal random numbers generated: {totalCount:N0}"
            printfn $"Total sum of all random numbers: {totalValue:N2}"
            printfn $"Random number mean: {(totalValue / float totalCount):N4}"
        with
        | :? AggregateException as e ->
            for inner in e.InnerExceptions do
                match inner with
                | :? TaskCanceledException as canc ->
                    if canc <> null then
                        printfn $"Task #{canc.Task.Id} cancelled"
                    else
                        printfn $"Exception: {inner.GetType().Name}"
                | _ -> ()

let ex = Example()
Thread.CurrentThread.Name <- "Main"
ex.Execute()

// The example displays output like the following:
//       Task 1 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,502.47
//       Random number mean: 0.5003
//
//       Task 0 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,445.63
//       Random number mean: 0.5002
//
//       Task 2 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,556.04
//       Random number mean: 0.5003
//
//       Task 3 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,178.87
//       Random number mean: 0.5001
//
//       Task 4 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,819.17
//       Random number mean: 0.4999
//
//       Task 5 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,190.58
//       Random number mean: 0.5001
//
//       Task 6 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,720.21
//       Random number mean: 0.4999
//
//       Task 7 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,000.96
//       Random number mean: 0.4995
//
//       Task 8 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,499.33
//       Random number mean: 0.4997
//
//       Task 9 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 1,000,193.25
//       Random number mean: 0.5001
//
//       Task 10 finished execution.
//       Random numbers generated: 2,000,000
//       Sum of random numbers: 999,960.82
//       Random number mean: 0.5000
//
//
//       Total random numbers generated: 22,000,000
//       Total sum of all random numbers: 11,000,067.33
//       Random number mean: 0.5000
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

Module Example16
    Dim source As New CancellationTokenSource()
    Dim randLock As New Object()
    Dim numericLock As New Object()
    Dim rand As New Random()
    Dim totalValue As Double = 0.0
    Dim totalCount As Integer = 0

    Public Sub Main()
        Dim tasks As New List(Of Task)()

        For ctr As Integer = 1 To 10
            Dim token As CancellationToken = source.Token
            Dim taskNo As Integer = ctr
            tasks.Add(Task.Run(
                   Sub()
                       Dim previous As Double = 0.0
                       Dim taskCtr As Integer = 0
                       Dim taskTotal As Double = 0.0
                       Dim result As Double = 0.0

                       For n As Integer = 1 To 2000000
                           ' Make sure there's no corruption of Random.
                           token.ThrowIfCancellationRequested()

                           SyncLock randLock
                               result = rand.NextDouble()
                           End SyncLock
                           ' Check for corruption of Random instance.
                           If result = previous AndAlso result = 0 Then
                               source.Cancel()
                           Else
                               previous = result
                           End If
                           taskCtr += 1
                           taskTotal += result
                       Next

                       ' Show result.
                       Console.WriteLine("Task {0} finished execution.", taskNo)
                       Console.WriteLine("Random numbers generated: {0:N0}", taskCtr)
                       Console.WriteLine("Sum of random numbers: {0:N2}", taskTotal)
                       Console.WriteLine("Random number mean: {0:N4}", taskTotal / taskCtr)
                       Console.WriteLine()

                       ' Update overall totals.
                       SyncLock numericLock
                           totalCount += taskCtr
                           totalValue += taskTotal
                       End SyncLock
                   End Sub, token))
        Next

        Try
            Task.WaitAll(tasks.ToArray())
            Console.WriteLine()
            Console.WriteLine("Total random numbers generated: {0:N0}", totalCount)
            Console.WriteLine("Total sum of all random numbers: {0:N2}", totalValue)
            Console.WriteLine("Random number mean: {0:N4}", totalValue / totalCount)
        Catch e As AggregateException
            For Each inner As Exception In e.InnerExceptions
                Dim canc As TaskCanceledException = TryCast(inner, TaskCanceledException)
                If canc IsNot Nothing Then
                    Console.WriteLine("Task #{0} cancelled.", canc.Task.Id)
                Else
                    Console.WriteLine("Exception: {0}", inner.GetType().Name)
                End If
            Next
        Finally
            source.Dispose()
        End Try
    End Sub
End Module
' The example displays output like the following:
'       Task 1 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,502.47
'       Random number mean: 0.5003
'       
'       Task 0 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,445.63
'       Random number mean: 0.5002
'       
'       Task 2 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,556.04
'       Random number mean: 0.5003
'       
'       Task 3 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,178.87
'       Random number mean: 0.5001
'       
'       Task 4 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,819.17
'       Random number mean: 0.4999
'       
'       Task 5 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,190.58
'       Random number mean: 0.5001
'       
'       Task 6 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,720.21
'       Random number mean: 0.4999
'       
'       Task 7 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,000.96
'       Random number mean: 0.4995
'       
'       Task 8 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,499.33
'       Random number mean: 0.4997
'       
'       Task 9 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 1,000,193.25
'       Random number mean: 0.5001
'       
'       Task 10 finished execution.
'       Random numbers generated: 2,000,000
'       Sum of random numbers: 999,960.82
'       Random number mean: 0.5000
'       
'       
'       Total random numbers generated: 22,000,000
'       Total sum of all random numbers: 11,000,067.33
'       Random number mean: 0.5000

Es unterscheidet sich von dem ersten Beispiel auf folgende Weise:

  • Die Variablen, um die Anzahl der generierten Zufallszahlen nachzuverfolgen, und ihre Summe in jedem Vorgang sind lokal für den Vorgang, sodass es nicht erforderlich ist, das ThreadStaticAttribute Attribut zu verwenden.
  • Die statische Task.WaitAll Methode wird verwendet, um sicherzustellen, dass der Standard Thread nicht abgeschlossen wird, bevor alle Aufgaben abgeschlossen sind. Das Objekt ist nicht erforderlich CountdownEvent .
  • Die Ausnahme, die aus dem Abbruch von Vorgängen resultiert, wird in der Task.WaitAll Methode angezeigt. Im vorherigen Beispiel wird es von jedem Thread behandelt.

Generieren verschiedener Arten von Zufallszahlen

Der Zufallszahlengenerator stellt Methoden bereit, mit denen Sie die folgenden Arten von Zufallszahlen generieren können:

  • Eine Reihe von Byte Werten. Sie bestimmen die Anzahl der Bytewerte, indem Sie ein Array, das initialisiert wurde, an die Anzahl der Elemente übergeben, die die Methode an die NextBytes Methode zurückgeben soll. Im folgenden Beispiel werden 20 Bytes generiert.

    Random rnd = new Random();
    Byte[] bytes = new Byte[20];
    rnd.NextBytes(bytes);
    for (int ctr = 1; ctr <= bytes.Length; ctr++)
    {
        Console.Write("{0,3}   ", bytes[ctr - 1]);
        if (ctr % 10 == 0) Console.WriteLine();
    }
    
    // The example displays output like the following:
    //       141    48   189    66   134   212   211    71   161    56
    //       181   166   220   133     9   252   222    57    62    62
    
    let rnd = Random()
    let bytes = Array.zeroCreate 20
    rnd.NextBytes bytes
    
    for i = 1 to bytes.Length do
        printf "%3i   " bytes.[i - 1]
        if (i % 10 = 0) then printfn ""
    
    // The example displays output like the following:
    //       141    48   189    66   134   212   211    71   161    56
    //       181   166   220   133     9   252   222    57    62    62
    
    Module Example9
        Public Sub Main()
            Dim rnd As New Random()
            Dim bytes(19) As Byte
            rnd.NextBytes(bytes)
            For ctr As Integer = 1 To bytes.Length
                Console.Write("{0,3}   ", bytes(ctr - 1))
                If ctr Mod 10 = 0 Then Console.WriteLine()
            Next
        End Sub
    End Module
    ' The example displays output like the following:
    '       141    48   189    66   134   212   211    71   161    56
    '       181   166   220   133     9   252   222    57    62    62
    
  • Eine einzelne ganze Zahl. Sie können auswählen, ob eine ganze Zahl zwischen 0 und einem Maximalwert (Int32.MaxValue - 1) durch Aufrufen der Next() Methode, eine ganze Zahl zwischen 0 und einem bestimmten Wert durch Aufrufen der Next(Int32) Methode oder eine ganze Zahl innerhalb eines Wertebereichs durch Aufrufen der Next(Int32, Int32) Methode erfolgen soll. In den parametrisierten Überladungen ist der angegebene Maximalwert exklusiv; d. h. die tatsächliche maximale Zahl, die generiert wird, ist ein Kleiner als der angegebene Wert.

    Im folgenden Beispiel wird die Next(Int32, Int32) Methode aufgerufen, um 10 Zufallszahlen zwischen -10 und 10 zu generieren. Beachten Sie, dass das zweite Argument der Methode die exklusive obere Grenze des Bereichs von Zufallswerten angibt, die von der Methode zurückgegeben werden. Mit anderen Worten, die größte ganze Zahl, die die Methode zurückgeben kann, ist ein kleiner als dieser Wert.

    Random rnd = new Random();
    for (int ctr = 0; ctr < 10; ctr++)
    {
        Console.Write("{0,3}   ", rnd.Next(-10, 11));
    }
    
    // The example displays output like the following:
    //    2     9    -3     2     4    -7    -3    -8    -8     5
    
    let rnd = Random()
    for i = 0 to 9 do 
        printf "%3i   " (rnd.Next(-10, 11))
    
    // The example displays output like the following:
    //    2     9    -3     2     4    -7    -3    -8    -8     5
    
    Module Example11
        Public Sub Main()
            Dim rnd As New Random()
            For ctr As Integer = 0 To 9
                Console.Write("{0,3}   ", rnd.Next(-10, 11))
            Next
        End Sub
    End Module
    ' The example displays output like the following:
    '    2     9    -3     2     4    -7    -3    -8    -8     5
    
  • Ein einzelner Gleitkommawert von 0,0 auf kleiner als 1,0 durch Aufrufen der NextDouble Methode. Die ausschließliche Obergrenze der Zufallszahl, die von der Methode zurückgegeben wird, ist 1, sodass ihre tatsächliche Obergrenze 0,99999999999978 ist. Im folgenden Beispiel werden 10 zufällige Gleitkommazahlen generiert.

    Random rnd = new Random();
    for (int ctr = 0; ctr < 10; ctr++)
    {
        Console.Write("{0,-19:R}   ", rnd.NextDouble());
        if ((ctr + 1) % 3 == 0) Console.WriteLine();
    }
    
    // The example displays output like the following:
    //    0.7911680553998649    0.0903414949264105    0.79776258291572455
    //    0.615568345233597     0.652644504165577     0.84023809378977776
    //    0.099662564741290441   0.91341467383942321  0.96018602045261581
    //    0.74772306473354022
    
    let rnd = Random()
    for i = 0 to 9 do 
        printf $"{rnd.NextDouble(),-19:R}   "
        if (i + 1) % 3 = 0 then printfn ""
    
    // The example displays output like the following:
    //    0.7911680553998649    0.0903414949264105    0.79776258291572455
    //    0.615568345233597     0.652644504165577     0.84023809378977776
    //    0.099662564741290441   0.91341467383942321  0.96018602045261581
    //    0.74772306473354022
    
    Module Example10
        Public Sub Main()
            Dim rnd As New Random()
            For ctr As Integer = 0 To 9
                Console.Write("{0,-19:R}   ", rnd.NextDouble())
                If (ctr + 1) Mod 3 = 0 Then Console.WriteLine()
            Next
        End Sub
    End Module
    ' The example displays output like the following:
    '    0.7911680553998649    0.0903414949264105    0.79776258291572455    
    '    0.615568345233597     0.652644504165577     0.84023809378977776   
    '    0.099662564741290441  0.91341467383942321   0.96018602045261581   
    '    0.74772306473354022
    

Wichtig

Mit der Next(Int32, Int32) Methode können Sie den Bereich der zurückgegebenen Zufallszahl angeben. Der Parameter, der maxValue die zurückgegebene Zahl im oberen Bereich angibt, ist jedoch ein exklusiver, nicht ein inklusiver Wert. Dies bedeutet, dass der Methodenaufruf Next(0, 100) einen Wert zwischen 0 und 99 und nicht zwischen 0 und 100 zurückgibt.

Sie können die Random Klasse auch für Aufgaben wie das Generieren zufälliger boolescher Werte, das Generieren zufälliger Gleitkommawerte in einem angegebenen Bereich, das Generieren zufälliger 64-Bit-Ganzzahlen und das Abrufen eines eindeutigen Elements aus einem Array oder einer Auflistung verwenden.

Ersetzen Sie Ihren eigenen Algorithmus

Sie können Ihren eigenen Zufallszahlengenerator implementieren, indem Sie von der Random Klasse erben und Ihren Zufallszahlengenerierungsalgorithmus bereitstellen. Um Ihren eigenen Algorithmus anzugeben, müssen Sie die Sample Methode überschreiben, die den Algorithmus zur Zufallszahlengenerierung implementiert. Sie sollten auch die Next()Methoden Next(Int32, Int32)und NextBytes Methoden außer Kraft setzen, um sicherzustellen, dass sie Die außerKraftsetzungsmethode Sample aufrufen. Sie müssen die Next(Int32) Methoden NextDouble und Methoden nicht überschreiben.

Ein Beispiel, das von der Random Klasse abgeleitet wird und seinen standardmäßigen Pseudo-Zufallszahlengenerator ändert, finden Sie auf der Sample Referenzseite.

Abrufen der gleichen Abfolge von Zufallswerten

Manchmal möchten Sie dieselbe Sequenz von Zufallszahlen in Softwaretestszenarien und im Spiel generieren. Das Testen mit derselben Sequenz von Zufallszahlen ermöglicht es Ihnen, Regressionen zu erkennen und Fehlerkorrekturen zu bestätigen. Wenn Sie dieselbe Sequenz von Zufallszahlen in Spielen verwenden, können Sie frühere Spiele wiedergeben.

Sie können dieselbe Sequenz von Zufallszahlen generieren, indem Sie dem Konstruktor denselben Ausgangswert Random(Int32) angeben. Der Seedwert stellt einen Startwert für den Pseudo-Zufallszahlengenerierungsalgorithmus bereit. Im folgenden Beispiel wird 100100 als beliebiger Seedwert verwendet, um das Random Objekt zu instanziieren, 20 zufällige Gleitkommawerte anzuzeigen und den Ausgangswert beizubehalten. Anschließend wird der Ausgangswert wiederhergestellt, ein neuer Zufallszahlengenerator instanziiert und dieselben 20 zufälligen Gleitkommawerte angezeigt. Beachten Sie, dass das Beispiel unterschiedliche Sequenzen von Zufallszahlen erzeugen kann, wenn sie in verschiedenen Versionen von .NET ausgeführt werden.

using System;
using System.IO;

public class Example12
{
    public static void Main()
    {
        int seed = 100100;
        ShowRandomNumbers(seed);
        Console.WriteLine();

        PersistSeed(seed);

        DisplayNewRandomNumbers();
    }

    private static void ShowRandomNumbers(int seed)
    {
        Random rnd = new Random(seed);
        for (int ctr = 0; ctr <= 20; ctr++)
            Console.WriteLine(rnd.NextDouble());
    }

    private static void PersistSeed(int seed)
    {
        FileStream fs = new FileStream(@".\seed.dat", FileMode.Create);
        BinaryWriter bin = new BinaryWriter(fs);
        bin.Write(seed);
        bin.Close();
    }

    private static void DisplayNewRandomNumbers()
    {
        FileStream fs = new FileStream(@".\seed.dat", FileMode.Open);
        BinaryReader bin = new BinaryReader(fs);
        int seed = bin.ReadInt32();
        bin.Close();

        Random rnd = new Random(seed);
        for (int ctr = 0; ctr <= 20; ctr++)
            Console.WriteLine(rnd.NextDouble());
    }
}
// The example displays output like the following:
//       0.500193602172748
//       0.0209461245783354
//       0.465869495396442
//       0.195512794514891
//       0.928583675496552
//       0.729333720509584
//       0.381455668891527
//       0.0508996467343064
//       0.019261200921266
//       0.258578445417145
//       0.0177532266908107
//       0.983277184415272
//       0.483650274334313
//       0.0219647376900375
//       0.165910115077118
//       0.572085966622497
//       0.805291457942357
//       0.927985211335116
//       0.4228545699375
//       0.523320379910674
//       0.157783938645285
//
//       0.500193602172748
//       0.0209461245783354
//       0.465869495396442
//       0.195512794514891
//       0.928583675496552
//       0.729333720509584
//       0.381455668891527
//       0.0508996467343064
//       0.019261200921266
//       0.258578445417145
//       0.0177532266908107
//       0.983277184415272
//       0.483650274334313
//       0.0219647376900375
//       0.165910115077118
//       0.572085966622497
//       0.805291457942357
//       0.927985211335116
//       0.4228545699375
//       0.523320379910674
//       0.157783938645285
open System
open System.IO

let showRandomNumbers seed =
    let rnd = Random seed
    for _ = 0 to 20 do 
        printfn $"{rnd.NextDouble()}"

let persistSeed (seed: int) =
    use bin = new BinaryWriter(new FileStream(@".\seed.dat", FileMode.Create))
    bin.Write seed

let displayNewRandomNumbers () =
    use bin = new BinaryReader(new FileStream(@".\seed.dat", FileMode.Open))
    let seed = bin.ReadInt32()

    let rnd = Random seed
    for _ = 0 to 20 do 
        printfn $"{rnd.NextDouble()}"

let seed = 100100
showRandomNumbers seed
printfn ""

persistSeed seed

displayNewRandomNumbers ()

// The example displays output like the following:
//       0.500193602172748
//       0.0209461245783354
//       0.465869495396442
//       0.195512794514891
//       0.928583675496552
//       0.729333720509584
//       0.381455668891527
//       0.0508996467343064
//       0.019261200921266
//       0.258578445417145
//       0.0177532266908107
//       0.983277184415272
//       0.483650274334313
//       0.0219647376900375
//       0.165910115077118
//       0.572085966622497
//       0.805291457942357
//       0.927985211335116
//       0.4228545699375
//       0.523320379910674
//       0.157783938645285
//
//       0.500193602172748
//       0.0209461245783354
//       0.465869495396442
//       0.195512794514891
//       0.928583675496552
//       0.729333720509584
//       0.381455668891527
//       0.0508996467343064
//       0.019261200921266
//       0.258578445417145
//       0.0177532266908107
//       0.983277184415272
//       0.483650274334313
//       0.0219647376900375
//       0.165910115077118
//       0.572085966622497
//       0.805291457942357
//       0.927985211335116
//       0.4228545699375
//       0.523320379910674
//       0.157783938645285
Imports System.IO

Module Example14
    Public Sub Main()
        Dim seed As Integer = 100100
        ShowRandomNumbers(seed)
        Console.WriteLine()

        PersistSeed(seed)

        DisplayNewRandomNumbers()
    End Sub

    Private Sub ShowRandomNumbers(seed As Integer)
        Dim rnd As New Random(seed)
        For ctr As Integer = 0 To 20
            Console.WriteLine(rnd.NextDouble())
        Next
    End Sub

    Private Sub PersistSeed(seed As Integer)
        Dim fs As New FileStream(".\seed.dat", FileMode.Create)
        Dim bin As New BinaryWriter(fs)
        bin.Write(seed)
        bin.Close()
    End Sub

    Private Sub DisplayNewRandomNumbers()
        Dim fs As New FileStream(".\seed.dat", FileMode.Open)
        Dim bin As New BinaryReader(fs)
        Dim seed As Integer = bin.ReadInt32()
        bin.Close()

        Dim rnd As New Random(seed)
        For ctr As Integer = 0 To 20
            Console.WriteLine(rnd.NextDouble())
        Next
    End Sub
End Module
' The example displays output like the following:
'       0.500193602172748
'       0.0209461245783354
'       0.465869495396442
'       0.195512794514891
'       0.928583675496552
'       0.729333720509584
'       0.381455668891527
'       0.0508996467343064
'       0.019261200921266
'       0.258578445417145
'       0.0177532266908107
'       0.983277184415272
'       0.483650274334313
'       0.0219647376900375
'       0.165910115077118
'       0.572085966622497
'       0.805291457942357
'       0.927985211335116
'       0.4228545699375
'       0.523320379910674
'       0.157783938645285
'       
'       0.500193602172748
'       0.0209461245783354
'       0.465869495396442
'       0.195512794514891
'       0.928583675496552
'       0.729333720509584
'       0.381455668891527
'       0.0508996467343064
'       0.019261200921266
'       0.258578445417145
'       0.0177532266908107
'       0.983277184415272
'       0.483650274334313
'       0.0219647376900375
'       0.165910115077118
'       0.572085966622497
'       0.805291457942357
'       0.927985211335116
'       0.4228545699375
'       0.523320379910674
'       0.157783938645285

Abrufen eindeutiger Sequenzen von Zufallszahlen

Die Bereitstellung unterschiedlicher Ausgangswerte für Instanzen der Random Klasse bewirkt, dass jeder Zufallszahlengenerator eine andere Abfolge von Werten erzeugt. Sie können einen Seedwert entweder explizit bereitstellen, indem Sie den Random(Int32) Konstruktor aufrufen oder implizit den Random() Konstruktor aufrufen. Die meisten Entwickler rufen den parameterlosen Konstruktor auf, der die Systemuhr verwendet. Im folgenden Beispiel wird dieser Ansatz verwendet, um zwei Random Instanzen zu instanziieren. Jede Instanz zeigt eine Reihe von 10 ganzzahligen Zufallszahlen an.

using System;
using System.Threading;

public class Example16
{
    public static void Main()
    {
        Console.WriteLine("Instantiating two random number generators...");
        Random rnd1 = new Random();
        Thread.Sleep(2000);
        Random rnd2 = new Random();

        Console.WriteLine("\nThe first random number generator:");
        for (int ctr = 1; ctr <= 10; ctr++)
            Console.WriteLine("   {0}", rnd1.Next());

        Console.WriteLine("\nThe second random number generator:");
        for (int ctr = 1; ctr <= 10; ctr++)
            Console.WriteLine("   {0}", rnd2.Next());
    }
}
// The example displays output like the following:
//       Instantiating two random number generators...
//
//       The first random number generator:
//          643164361
//          1606571630
//          1725607587
//          2138048432
//          496874898
//          1969147632
//          2034533749
//          1840964542
//          412380298
//          47518930
//
//       The second random number generator:
//          1251659083
//          1514185439
//          1465798544
//          517841554
//          1821920222
//          195154223
//          1538948391
//          1548375095
//          546062716
//          897797880
open System
open System.Threading

printfn "Instantiating two random number generators..."
let rnd1 = Random()
Thread.Sleep 2000
let rnd2 = Random()

printfn "\nThe first random number generator:"
for _ = 1 to 10 do 
    printfn $"   {rnd1.Next()}"

printfn "\nThe second random number generator:"
for _ = 1 to 10 do 
    printfn $"   {rnd2.Next()}"

// The example displays output like the following:
//       Instantiating two random number generators...
//
//       The first random number generator:
//          643164361
//          1606571630
//          1725607587
//          2138048432
//          496874898
//          1969147632
//          2034533749
//          1840964542
//          412380298
//          47518930
//
//       The second random number generator:
//          1251659083
//          1514185439
//          1465798544
//          517841554
//          1821920222
//          195154223
//          1538948391
//          1548375095
//          546062716
//          897797880
Imports System.Threading

Module Example17
    Public Sub Main()
        Console.WriteLine("Instantiating two random number generators...")
        Dim rnd1 As New Random()
        Thread.Sleep(2000)
        Dim rnd2 As New Random()
        Console.WriteLine()

        Console.WriteLine("The first random number generator:")
        For ctr As Integer = 1 To 10
            Console.WriteLine("   {0}", rnd1.Next())
        Next
        Console.WriteLine()

        Console.WriteLine("The second random number generator:")
        For ctr As Integer = 1 To 10
            Console.WriteLine("   {0}", rnd2.Next())
        Next
    End Sub
End Module
' The example displays output like the following:
'       Instantiating two random number generators...
'       
'       The first random number generator:
'          643164361
'          1606571630
'          1725607587
'          2138048432
'          496874898
'          1969147632
'          2034533749
'          1840964542
'          412380298
'          47518930
'       
'       The second random number generator:
'          1251659083
'          1514185439
'          1465798544
'          517841554
'          1821920222
'          195154223
'          1538948391
'          1548375095
'          546062716
'          897797880

Aufgrund der begrenzten Auflösung erkennt die Systemuhr jedoch keine Zeitunterschiede, die weniger als etwa 15 Millisekunden sind. Wenn Ihr Code daher die Random() Überladung in .NET Framework aufruft, um zwei Random Objekte nacheinander zu instanziieren, stellen Sie möglicherweise versehentlich die Objekte mit identischen Startwerten bereit. (Die Random Klasse in .NET Core hat diese Einschränkung nicht.) Um dies im vorherigen Beispiel anzuzeigen, kommentieren Sie den Thread.Sleep Methodenaufruf aus, und kompilieren und führen Sie das Beispiel erneut aus.

Um dies zu verhindern, empfehlen wir, ein einzelnes Random Objekt anstelle mehrerer objekte zu instanziieren. Da Random jedoch nicht threadsicher ist, müssen Sie ein Synchronisierungsgerät verwenden, wenn Sie über mehrere Threads auf eine Random Instanz zugreifen. Weitere Informationen finden Sie im Abschnitt "Threadsicherheit ". Alternativ können Sie einen Verzögerungsmechanismus verwenden, z. B. die Sleep im vorherigen Beispiel verwendete Methode, um sicherzustellen, dass die Instanziierungen mehr als 15 Millisekunden auseinander auftreten.

Abrufen ganzzahliger Zahlen in einem angegebenen Bereich

Sie können ganze Zahlen in einem angegebenen Bereich abrufen, indem Sie die Next(Int32, Int32) Methode aufrufen, mit der Sie sowohl die untere als auch die obere Grenze der Zahlen angeben können, die der Zufallszahlengenerator zurückgeben soll. Die obere Grenze ist ein exklusiver, nicht ein inklusiver Wert. Das heißt, sie ist nicht im Wertebereich enthalten, der von der Methode zurückgegeben wird. Im folgenden Beispiel wird diese Methode verwendet, um zufällige ganze Zahlen zwischen -10 und 10 zu generieren. Beachten Sie, dass es 11 angibt, bei dem es sich um einen größer als den gewünschten Wert handelt, als Wert des maxValue Arguments im Methodenaufruf.

Random rnd = new Random();
for (int ctr = 1; ctr <= 15; ctr++)
{
    Console.Write("{0,3}    ", rnd.Next(-10, 11));
    if (ctr % 5 == 0) Console.WriteLine();
}

// The example displays output like the following:
//        -2     -5     -1     -2     10
//        -3      6     -4     -8      3
//        -7     10      5     -2      4
let rnd = Random()
for i = 1 to 15 do 
    printf "%3i    " (rnd.Next(-10, 11))
    if i % 5 = 0 then printfn ""
// The example displays output like the following:
//        -2     -5     -1     -2     10
//        -3      6     -4     -8      3
//        -7     10      5     -2      4
Module Example12
    Public Sub Main()
        Dim rnd As New Random()
        For ctr As Integer = 1 To 15
            Console.Write("{0,3}    ", rnd.Next(-10, 11))
            If ctr Mod 5 = 0 Then Console.WriteLine()
        Next
    End Sub
End Module
' The example displays output like the following:
'        -2     -5     -1     -2     10
'        -3      6     -4     -8      3
'        -7     10      5     -2      4

Abrufen ganzzahliger Zahlen mit einer angegebenen Anzahl von Ziffern

Sie können die Next(Int32, Int32) Methode aufrufen, um Nummern mit einer angegebenen Anzahl von Ziffern abzurufen. Um beispielsweise Zahlen mit vier Ziffern abzurufen (d. h. Zahlen, die zwischen 1000 und 9999 liegen), rufen Sie die Next(Int32, Int32) Methode mit dem minValue Wert 1000 und dem maxValue Wert 10000 auf, wie im folgenden Beispiel gezeigt.

Random rnd = new Random();
for (int ctr = 1; ctr <= 50; ctr++)
{
    Console.Write("{0,3}    ", rnd.Next(1000, 10000));
    if (ctr % 10 == 0) Console.WriteLine();
}

// The example displays output like the following:
//    9570    8979    5770    1606    3818    4735    8495    7196    7070    2313
//    5279    6577    5104    5734    4227    3373    7376    6007    8193    5540
//    7558    3934    3819    7392    1113    7191    6947    4963    9179    7907
//    3391    6667    7269    1838    7317    1981    5154    7377    3297    5320
//    9869    8694    2684    4949    2999    3019    2357    5211    9604    2593
let rnd = Random()
for i = 1 to 50 do
    printf "%3i    " (rnd.Next(1000, 10000))
    if i % 10 = 0 then printfn ""

// The example displays output like the following:
//    9570    8979    5770    1606    3818    4735    8495    7196    7070    2313
//    5279    6577    5104    5734    4227    3373    7376    6007    8193    5540
//    7558    3934    3819    7392    1113    7191    6947    4963    9179    7907
//    3391    6667    7269    1838    7317    1981    5154    7377    3297    5320
//    9869    8694    2684    4949    2999    3019    2357    5211    9604    2593
Module Example13
    Public Sub Main()
        Dim rnd As New Random()
        For ctr As Integer = 1 To 50
            Console.Write("{0,3}    ", rnd.Next(1000, 10000))
            If ctr Mod 10 = 0 Then Console.WriteLine()
        Next
    End Sub
End Module
' The example displays output like the following:
'    9570    8979    5770    1606    3818    4735    8495    7196    7070    2313
'    5279    6577    5104    5734    4227    3373    7376    6007    8193    5540
'    7558    3934    3819    7392    1113    7191    6947    4963    9179    7907
'    3391    6667    7269    1838    7317    1981    5154    7377    3297    5320
'    9869    8694    2684    4949    2999    3019    2357    5211    9604    2593

Abrufen von Gleitkommawerten in einem angegebenen Bereich

Die NextDouble Methode gibt zufällige Gleitkommawerte zurück, die zwischen 0 und weniger als 1 liegen. Sie möchten jedoch häufig Zufallswerte in einem anderen Bereich generieren.

Wenn das Intervall zwischen den minimalen und den maximal gewünschten Werten 1 ist, können Sie die Differenz zwischen dem gewünschten Anfangsintervall und 0 der von der NextDouble Methode zurückgegebenen Zahl hinzufügen. Im folgenden Beispiel werden 10 Zufallszahlen zwischen -1 und 0 generiert.

Random rnd = new Random();
for (int ctr = 1; ctr <= 10; ctr++)
    Console.WriteLine(rnd.NextDouble() - 1);

// The example displays output like the following:
//       -0.930412760437658
//       -0.164699016215605
//       -0.9851692803135
//       -0.43468508843085
//       -0.177202483255976
//       -0.776813320245972
//       -0.0713201854710096
//       -0.0912875561468711
//       -0.540621722368813
//       -0.232211863730201
let rnd = Random()

for _ = 1 to 10 do
    printfn "%O" (rnd.NextDouble() - 1.0)

// The example displays output like the following:
//       -0.930412760437658
//       -0.164699016215605
//       -0.9851692803135
//       -0.43468508843085
//       -0.177202483255976
//       -0.776813320245972
//       -0.0713201854710096
//       -0.0912875561468711
//       -0.540621722368813
//       -0.232211863730201
Module Example6
    Public Sub Main()
        Dim rnd As New Random()
        For ctr As Integer = 1 To 10
            Console.WriteLine(rnd.NextDouble() - 1)
        Next
    End Sub
End Module
' The example displays output like the following:
'       -0.930412760437658
'       -0.164699016215605
'       -0.9851692803135
'       -0.43468508843085
'       -0.177202483255976
'       -0.776813320245972
'       -0.0713201854710096
'       -0.0912875561468711
'       -0.540621722368813
'       -0.232211863730201

Um zufällige Gleitkommazahlen zu generieren, deren untere Grenze 0 ist, aber die obere Grenze größer als 1 ist (oder bei negativen Zahlen, deren untere Grenze kleiner als -1 und obere Grenze 0 ist), multiplizieren Sie die Zufallszahl mit der Nicht-Null-Grenze. Im folgenden Beispiel wird dies ausgeführt, um 20 Millionen zufällige Gleitkommazahlen zu generieren, die zwischen 0 und Int64.MaxValue0 liegen. In zeigt auch die Verteilung der Zufallswerte an, die von der Methode generiert werden.

const long ONE_TENTH = 922337203685477581;

Random rnd = new Random();
double number;
int[] count = new int[10];

// Generate 20 million integer values between.
for (int ctr = 1; ctr <= 20000000; ctr++)
{
    number = rnd.NextDouble() * Int64.MaxValue;
    // Categorize random numbers into 10 groups.
    count[(int)(number / ONE_TENTH)]++;
}
// Display breakdown by range.
Console.WriteLine("{0,28} {1,32}   {2,7}\n", "Range", "Count", "Pct.");
for (int ctr = 0; ctr <= 9; ctr++)
    Console.WriteLine("{0,25:N0}-{1,25:N0}  {2,8:N0}   {3,7:P2}", ctr * ONE_TENTH,
                       ctr < 9 ? ctr * ONE_TENTH + ONE_TENTH - 1 : Int64.MaxValue,
                       count[ctr], count[ctr] / 20000000.0);

// The example displays output like the following:
//                           Range                            Count      Pct.
//
//                            0-  922,337,203,685,477,580  1,996,148    9.98 %
//      922,337,203,685,477,581-1,844,674,407,370,955,161  2,000,293   10.00 %
//    1,844,674,407,370,955,162-2,767,011,611,056,432,742  2,000,094   10.00 %
//    2,767,011,611,056,432,743-3,689,348,814,741,910,323  2,000,159   10.00 %
//    3,689,348,814,741,910,324-4,611,686,018,427,387,904  1,999,552   10.00 %
//    4,611,686,018,427,387,905-5,534,023,222,112,865,485  1,998,248    9.99 %
//    5,534,023,222,112,865,486-6,456,360,425,798,343,066  2,000,696   10.00 %
//    6,456,360,425,798,343,067-7,378,697,629,483,820,647  2,001,637   10.01 %
//    7,378,697,629,483,820,648-8,301,034,833,169,298,228  2,002,870   10.01 %
//    8,301,034,833,169,298,229-9,223,372,036,854,775,807  2,000,303   10.00 %
[<Literal>]
let ONE_TENTH = 922337203685477581L

let rnd = Random()

// Generate 20 million random integers.
let count =
    Array.init 20000000 (fun _ -> rnd.NextDouble() * (float Int64.MaxValue) )
    |> Array.countBy (fun x -> x / (float ONE_TENTH) |> int ) // Categorize into 10 groups and count them.
    |> Array.map snd

// Display breakdown by range.
printfn "%28s %32s   %7s\n" "Range" "Count" "Pct."
for i = 0 to 9 do
    let r1 = int64 i * ONE_TENTH
    let r2 = if i < 9 then r1 + ONE_TENTH - 1L else Int64.MaxValue
    printfn $"{r1,25:N0}-{r2,25:N0}  {count.[i],8:N0}   {float count.[i] / 20000000.0,7:P2}"

// The example displays output like the following:
//                           Range                            Count      Pct.
//
//                            0-  922,337,203,685,477,580  1,996,148    9.98 %
//      922,337,203,685,477,581-1,844,674,407,370,955,161  2,000,293   10.00 %
//    1,844,674,407,370,955,162-2,767,011,611,056,432,742  2,000,094   10.00 %
//    2,767,011,611,056,432,743-3,689,348,814,741,910,323  2,000,159   10.00 %
//    3,689,348,814,741,910,324-4,611,686,018,427,387,904  1,999,552   10.00 %
//    4,611,686,018,427,387,905-5,534,023,222,112,865,485  1,998,248    9.99 %
//    5,534,023,222,112,865,486-6,456,360,425,798,343,066  2,000,696   10.00 %
//    6,456,360,425,798,343,067-7,378,697,629,483,820,647  2,001,637   10.01 %
//    7,378,697,629,483,820,648-8,301,034,833,169,298,228  2,002,870   10.01 %
//    8,301,034,833,169,298,229-9,223,372,036,854,775,807  2,000,303   10.00 %
Module Example5
    Public Sub Main()
        Const ONE_TENTH As Long = 922337203685477581

        Dim rnd As New Random()
        Dim number As Long
        Dim count(9) As Integer

        ' Generate 20 million integer values.
        For ctr As Integer = 1 To 20000000
            number = CLng(rnd.NextDouble() * Int64.MaxValue)
            ' Categorize random numbers.
            count(CInt(number \ ONE_TENTH)) += 1
        Next
        ' Display breakdown by range.
        Console.WriteLine("{0,28} {1,32}   {2,7}", "Range", "Count", "Pct.")
        Console.WriteLine()
        For ctr As Integer = 0 To 9
            Console.WriteLine("{0,25:N0}-{1,25:N0}  {2,8:N0}   {3,7:P2}", ctr * ONE_TENTH,
                            If(ctr < 9, ctr * ONE_TENTH + ONE_TENTH - 1, Int64.MaxValue),
                            count(ctr), count(ctr) / 20000000)
        Next
    End Sub
End Module
' The example displays output like the following:
'                           Range                            Count      Pct.
'    
'                            0-  922,337,203,685,477,580  1,996,148    9.98 %
'      922,337,203,685,477,581-1,844,674,407,370,955,161  2,000,293   10.00 %
'    1,844,674,407,370,955,162-2,767,011,611,056,432,742  2,000,094   10.00 %
'    2,767,011,611,056,432,743-3,689,348,814,741,910,323  2,000,159   10.00 %
'    3,689,348,814,741,910,324-4,611,686,018,427,387,904  1,999,552   10.00 %
'    4,611,686,018,427,387,905-5,534,023,222,112,865,485  1,998,248    9.99 %
'    5,534,023,222,112,865,486-6,456,360,425,798,343,066  2,000,696   10.00 %
'    6,456,360,425,798,343,067-7,378,697,629,483,820,647  2,001,637   10.01 %
'    7,378,697,629,483,820,648-8,301,034,833,169,298,228  2,002,870   10.01 %
'    8,301,034,833,169,298,229-9,223,372,036,854,775,807  2,000,303   10.00 %

Verwenden Sie die folgende Formel, um zufällige Gleitkommazahlen zwischen zwei beliebigen Werten wie die Next(Int32, Int32) Methode für ganze Zahlen zu generieren:

Random.NextDouble() * (maxValue - minValue) + minValue

Im folgenden Beispiel werden 1 Millionen Zufallszahlen generiert, die zwischen 10,0 und 11,0 liegen, und zeigt ihre Verteilung an.

Random rnd = new Random();
int lowerBound = 10;
int upperBound = 11;
int[] range = new int[10];
for (int ctr = 1; ctr <= 1000000; ctr++)
{
    Double value = rnd.NextDouble() * (upperBound - lowerBound) + lowerBound;
    range[(int)Math.Truncate((value - lowerBound) * 10)]++;
}

for (int ctr = 0; ctr <= 9; ctr++)
{
    Double lowerRange = 10 + ctr * .1;
    Console.WriteLine("{0:N1} to {1:N1}: {2,8:N0}  ({3,7:P2})",
                      lowerRange, lowerRange + .1, range[ctr],
                      range[ctr] / 1000000.0);
}

// The example displays output like the following:
//       10.0 to 10.1:   99,929  ( 9.99 %)
//       10.1 to 10.2:  100,189  (10.02 %)
//       10.2 to 10.3:   99,384  ( 9.94 %)
//       10.3 to 10.4:  100,240  (10.02 %)
//       10.4 to 10.5:   99,397  ( 9.94 %)
//       10.5 to 10.6:  100,580  (10.06 %)
//       10.6 to 10.7:  100,293  (10.03 %)
//       10.7 to 10.8:  100,135  (10.01 %)
//       10.8 to 10.9:   99,905  ( 9.99 %)
//       10.9 to 11.0:   99,948  ( 9.99 %)
let rnd = Random()

let lowerBound = 10.0
let upperBound = 11.0

let range =
    Array.init 1000000 (fun _ -> rnd.NextDouble() * (upperBound - lowerBound) +  lowerBound)
    |> Array.countBy (fun x -> Math.Truncate((x - lowerBound) * 10.0) |> int)
    |> Array.map snd

for i = 0 to 9 do 
    let lowerRange = 10.0 + float i * 0.1
    printfn $"{lowerRange:N1} to {lowerRange + 0.1:N1}: {range.[i],8:N0}  ({float range.[i] / 1000000.0,6:P2})"

// The example displays output like the following:
//       10.0 to 10.1:   99,929  ( 9.99 %)
//       10.1 to 10.2:  100,189  (10.02 %)
//       10.2 to 10.3:   99,384  ( 9.94 %)
//       10.3 to 10.4:  100,240  (10.02 %)
//       10.4 to 10.5:   99,397  ( 9.94 %)
//       10.5 to 10.6:  100,580  (10.06 %)
//       10.6 to 10.7:  100,293  (10.03 %)
//       10.7 to 10.8:  100,135  (10.01 %)
//       10.8 to 10.9:   99,905  ( 9.99 %)
//       10.9 to 11.0:   99,948  ( 9.99 %)
Module Example7
    Public Sub Main()
        Dim rnd As New Random()
        Dim lowerBound As Integer = 10
        Dim upperBound As Integer = 11
        Dim range(9) As Integer
        For ctr As Integer = 1 To 1000000
            Dim value As Double = rnd.NextDouble() * (upperBound - lowerBound) + lowerBound
            range(CInt(Math.Truncate((value - lowerBound) * 10))) += 1
        Next

        For ctr As Integer = 0 To 9
            Dim lowerRange As Double = 10 + ctr * 0.1
            Console.WriteLine("{0:N1} to {1:N1}: {2,8:N0}  ({3,7:P2})",
                           lowerRange, lowerRange + 0.1, range(ctr),
                           range(ctr) / 1000000.0)
        Next
    End Sub
End Module
' The example displays output like the following:
'       10.0 to 10.1:   99,929  ( 9.99 %)
'       10.1 to 10.2:  100,189  (10.02 %)
'       10.2 to 10.3:   99,384  ( 9.94 %)
'       10.3 to 10.4:  100,240  (10.02 %)
'       10.4 to 10.5:   99,397  ( 9.94 %)
'       10.5 to 10.6:  100,580  (10.06 %)
'       10.6 to 10.7:  100,293  (10.03 %)
'       10.7 to 10.8:  100,135  (10.01 %)
'       10.8 to 10.9:   99,905  ( 9.99 %)
'       10.9 to 11.0:   99,948  ( 9.99 %)

Generieren zufälliger boolescher Werte

Die Random Klasse stellt keine Methoden bereit, die Werte generieren Boolean . Sie können jedoch ihre eigene Klasse oder Methode definieren, um dies zu tun. Im folgenden Beispiel wird eine Klasse mit BooleanGeneratoreiner einzigen Methode NextBooleandefiniert. Die BooleanGenerator Klasse speichert ein Random Objekt als private Variable. Die NextBoolean Methode ruft die Random.Next(Int32, Int32) Methode auf und übergibt das Ergebnis an die Convert.ToBoolean(Int32) Methode. Beachten Sie, dass 2 als Argument verwendet wird, um die obere Grenze der Zufallszahl anzugeben. Da dies ein exklusiver Wert ist, gibt der Methodenaufruf entweder 0 oder 1 zurück.

using System;

public class Example1
{
    public static void Main()
    {
        // Instantiate the Boolean generator.
        BooleanGenerator boolGen = new BooleanGenerator();
        int totalTrue = 0, totalFalse = 0;

        // Generate 1,0000 random Booleans, and keep a running total.
        for (int ctr = 0; ctr < 1000000; ctr++)
        {
            bool value = boolGen.NextBoolean();
            if (value)
                totalTrue++;
            else
                totalFalse++;
        }
        Console.WriteLine("Number of true values:  {0,7:N0} ({1:P3})",
                          totalTrue,
                          ((double)totalTrue) / (totalTrue + totalFalse));
        Console.WriteLine("Number of false values: {0,7:N0} ({1:P3})",
                          totalFalse,
                          ((double)totalFalse) / (totalTrue + totalFalse));
    }
}

public class BooleanGenerator
{
    Random rnd;

    public BooleanGenerator()
    {
        rnd = new Random();
    }

    public bool NextBoolean()
    {
        return rnd.Next(0, 2) == 1;
    }
}
// The example displays output like the following:
//       Number of true values:  500,004 (50.000 %)
//       Number of false values: 499,996 (50.000 %)
open System

type BooleanGenerator() =
    let rnd = Random()

    member _.NextBoolean() =
        rnd.Next(0, 2) = 1

let boolGen = BooleanGenerator()
let mutable totalTrue, totalFalse = 0, 0

for _ = 1 to 1000000 do
    let value = boolGen.NextBoolean()
    if value then 
        totalTrue <- totalTrue + 1
    else 
        totalFalse <- totalFalse + 1

printfn $"Number of true values:  {totalTrue,7:N0} ({(double totalTrue) / double (totalTrue + totalFalse):P3})"
printfn $"Number of false values: {totalFalse,7:N0} ({(double totalFalse) / double (totalTrue + totalFalse):P3})"

// The example displays output like the following:
//       Number of true values:  500,004 (50.000 %)
//       Number of false values: 499,996 (50.000 %)
Module Example2
    Public Sub Main()
        ' Instantiate the Boolean generator.
        Dim boolGen As New BooleanGenerator()
        Dim totalTrue, totalFalse As Integer

        ' Generate 1,0000 random Booleans, and keep a running total.
        For ctr As Integer = 0 To 9999999
            Dim value As Boolean = boolGen.NextBoolean()
            If value Then
                totalTrue += 1
            Else
                totalFalse += 1
            End If
        Next
        Console.WriteLine("Number of true values:  {0,7:N0} ({1:P3})",
                        totalTrue,
                        totalTrue / (totalTrue + totalFalse))
        Console.WriteLine("Number of false values: {0,7:N0} ({1:P3})",
                        totalFalse,
                        totalFalse / (totalTrue + totalFalse))
    End Sub
End Module

Public Class BooleanGenerator
   Dim rnd As Random
   
   Public Sub New()
      rnd = New Random()
   End Sub

   Public Function NextBoolean() As Boolean
      Return Convert.ToBoolean(rnd.Next(0, 2))
   End Function
End Class
' The example displays the following output:
'       Number of true values:  500,004 (50.000 %)
'       Number of false values: 499,996 (50.000 %)

Anstatt eine separate Klasse zum Generieren von Zufallswerten Boolean zu erstellen, könnte das Beispiel einfach eine einzelne Methode definiert haben. In diesem Fall sollte das Random Objekt jedoch als Variable auf Klassenebene definiert worden sein, um zu vermeiden, dass eine neue Random Instanz in jedem Methodenaufruf instanziiert wird. In Visual Basic kann die Zufällige Instanz als statische Variable in der NextBoolean Methode definiert werden. Im folgenden Beispiel wird eine Implementierung bereitgestellt.

Random rnd = new Random();

int totalTrue = 0, totalFalse = 0;

// Generate 1,000,000 random Booleans, and keep a running total.
for (int ctr = 0; ctr < 1000000; ctr++)
{
    bool value = NextBoolean();
    if (value)
        totalTrue++;
    else
        totalFalse++;
}
Console.WriteLine("Number of true values:  {0,7:N0} ({1:P3})",
                  totalTrue,
                  ((double)totalTrue) / (totalTrue + totalFalse));
Console.WriteLine("Number of false values: {0,7:N0} ({1:P3})",
                  totalFalse,
                  ((double)totalFalse) / (totalTrue + totalFalse));

bool NextBoolean()
{
    return rnd.Next(0, 2) == 1;
}

// The example displays output like the following:
//       Number of true values:  499,777 (49.978 %)
//       Number of false values: 500,223 (50.022 %)
let rnd = Random()

let nextBool () =
    rnd.Next(0, 2) = 1

let mutable totalTrue, totalFalse = 0, 0

for _ = 1 to 1000000 do
    let value = nextBool ()
    if value then 
        totalTrue <- totalTrue + 1
    else 
        totalFalse <- totalFalse + 1

printfn $"Number of true values:  {totalTrue,7:N0} ({(double totalTrue) / double (totalTrue + totalFalse):P3})"
printfn $"Number of false values: {totalFalse,7:N0} ({(double totalFalse) / double (totalTrue + totalFalse):P3})"

// The example displays output like the following:
//       Number of true values:  499,777 (49.978 %)
//       Number of false values: 500,223 (50.022 %)
Module Example3
    Public Sub Main()
        Dim totalTrue, totalFalse As Integer

        ' Generate 1,0000 random Booleans, and keep a running total.
        For ctr As Integer = 0 To 9999999
            Dim value As Boolean = NextBoolean()
            If value Then
                totalTrue += 1
            Else
                totalFalse += 1
            End If
        Next
        Console.WriteLine("Number of true values:  {0,7:N0} ({1:P3})",
                        totalTrue,
                        totalTrue / (totalTrue + totalFalse))
        Console.WriteLine("Number of false values: {0,7:N0} ({1:P3})",
                        totalFalse,
                        totalFalse / (totalTrue + totalFalse))
    End Sub

    Public Function NextBoolean() As Boolean
        Static rnd As New Random()
        Return Convert.ToBoolean(rnd.Next(0, 2))
    End Function
End Module
' The example displays the following output:
'       Number of true values:  499,777 (49.978 %)
'       Number of false values: 500,223 (50.022 %)

Generieren zufälliger 64-Bit-Ganzzahlen

Die Überladungen der Next Methode geben 32-Bit-Ganzzahlen zurück. In einigen Fällen möchten Sie jedoch möglicherweise mit 64-Bit-Ganzzahlen arbeiten. Sie können dies wie folgt tun:

  1. Rufen Sie die NextDouble Methode auf, um einen Gleitkommawert mit doppelter Genauigkeit abzurufen.

  2. Multiplizieren Sie diesen Wert mit Int64.MaxValue.

Im folgenden Beispiel wird diese Technik verwendet, um 20 Millionen zufällig lange ganze Zahlen zu generieren und sie in 10 gleichen Gruppen zu kategorisieren. Anschließend wird die Verteilung der Zufallszahlen ausgewertet, indem die Zahl in jeder Gruppe von 0 bis Int64.MaxValuegezählt wird. Wie die Ausgabe aus dem Beispiel zeigt, werden die Zahlen mehr oder weniger gleichmäßig über den Bereich einer langen ganzzahligen Zahl verteilt.

const long ONE_TENTH = 922337203685477581;

Random rnd = new Random();
long number;
int[] count = new int[10];

// Generate 20 million long integers.
for (int ctr = 1; ctr <= 20000000; ctr++)
{
    number = (long)(rnd.NextDouble() * Int64.MaxValue);
    // Categorize random numbers.
    count[(int)(number / ONE_TENTH)]++;
}
// Display breakdown by range.
Console.WriteLine("{0,28} {1,32}   {2,7}\n", "Range", "Count", "Pct.");
for (int ctr = 0; ctr <= 9; ctr++)
    Console.WriteLine("{0,25:N0}-{1,25:N0}  {2,8:N0}   {3,7:P2}", ctr * ONE_TENTH,
                       ctr < 9 ? ctr * ONE_TENTH + ONE_TENTH - 1 : Int64.MaxValue,
                       count[ctr], count[ctr] / 20000000.0);

// The example displays output like the following:
//                           Range                            Count      Pct.
//
//                            0-  922,337,203,685,477,580  1,996,148    9.98 %
//      922,337,203,685,477,581-1,844,674,407,370,955,161  2,000,293   10.00 %
//    1,844,674,407,370,955,162-2,767,011,611,056,432,742  2,000,094   10.00 %
//    2,767,011,611,056,432,743-3,689,348,814,741,910,323  2,000,159   10.00 %
//    3,689,348,814,741,910,324-4,611,686,018,427,387,904  1,999,552   10.00 %
//    4,611,686,018,427,387,905-5,534,023,222,112,865,485  1,998,248    9.99 %
//    5,534,023,222,112,865,486-6,456,360,425,798,343,066  2,000,696   10.00 %
//    6,456,360,425,798,343,067-7,378,697,629,483,820,647  2,001,637   10.01 %
//    7,378,697,629,483,820,648-8,301,034,833,169,298,228  2,002,870   10.01 %
//    8,301,034,833,169,298,229-9,223,372,036,854,775,807  2,000,303   10.00 %
[<Literal>]
let ONE_TENTH = 922337203685477581L

let rnd = Random()

let count =
    // Generate 20 million random long integers.
    Array.init 20000000 (fun _ -> rnd.NextDouble() * (float Int64.MaxValue) |> int64 )
    |> Array.countBy (fun x -> x / ONE_TENTH) // Categorize and count random numbers.
    |> Array.map snd

// Display breakdown by range.
printfn "%28s %32s   %7s\n" "Range" "Count" "Pct."
for i = 0 to 9 do
    let r1 = int64 i * ONE_TENTH
    let r2 = if i < 9 then r1 + ONE_TENTH - 1L else Int64.MaxValue
    printfn $"{r1,25:N0}-{r2,25:N0}  {count.[i],8:N0}   {float count.[i] / 20000000.0,7:P2}"

// The example displays output like the following:
//                           Range                            Count      Pct.
//
//                            0-  922,337,203,685,477,580  1,996,148    9.98 %
//      922,337,203,685,477,581-1,844,674,407,370,955,161  2,000,293   10.00 %
//    1,844,674,407,370,955,162-2,767,011,611,056,432,742  2,000,094   10.00 %
//    2,767,011,611,056,432,743-3,689,348,814,741,910,323  2,000,159   10.00 %
//    3,689,348,814,741,910,324-4,611,686,018,427,387,904  1,999,552   10.00 %
//    4,611,686,018,427,387,905-5,534,023,222,112,865,485  1,998,248    9.99 %
//    5,534,023,222,112,865,486-6,456,360,425,798,343,066  2,000,696   10.00 %
//    6,456,360,425,798,343,067-7,378,697,629,483,820,647  2,001,637   10.01 %
//    7,378,697,629,483,820,648-8,301,034,833,169,298,228  2,002,870   10.01 %
//    8,301,034,833,169,298,229-9,223,372,036,854,775,807  2,000,303   10.00 %
Module Example8
    Public Sub Main()
        Const ONE_TENTH As Long = 922337203685477581

        Dim rnd As New Random()
        Dim number As Long
        Dim count(9) As Integer

        ' Generate 20 million long integers.
        For ctr As Integer = 1 To 20000000
            number = CLng(rnd.NextDouble() * Int64.MaxValue)
            ' Categorize random numbers.
            count(CInt(number \ ONE_TENTH)) += 1
        Next
        ' Display breakdown by range.
        Console.WriteLine("{0,28} {1,32}   {2,7}", "Range", "Count", "Pct.")
        Console.WriteLine()
        For ctr As Integer = 0 To 9
            Console.WriteLine("{0,25:N0}-{1,25:N0}  {2,8:N0}   {3,7:P2}", ctr * ONE_TENTH,
                            If(ctr < 9, ctr * ONE_TENTH + ONE_TENTH - 1, Int64.MaxValue),
                            count(ctr), count(ctr) / 20000000)
        Next
    End Sub
End Module
' The example displays output like the following:
'                           Range                            Count      Pct.
'    
'                            0-  922,337,203,685,477,580  1,996,148    9.98 %
'      922,337,203,685,477,581-1,844,674,407,370,955,161  2,000,293   10.00 %
'    1,844,674,407,370,955,162-2,767,011,611,056,432,742  2,000,094   10.00 %
'    2,767,011,611,056,432,743-3,689,348,814,741,910,323  2,000,159   10.00 %
'    3,689,348,814,741,910,324-4,611,686,018,427,387,904  1,999,552   10.00 %
'    4,611,686,018,427,387,905-5,534,023,222,112,865,485  1,998,248    9.99 %
'    5,534,023,222,112,865,486-6,456,360,425,798,343,066  2,000,696   10.00 %
'    6,456,360,425,798,343,067-7,378,697,629,483,820,647  2,001,637   10.01 %
'    7,378,697,629,483,820,648-8,301,034,833,169,298,228  2,002,870   10.01 %
'    8,301,034,833,169,298,229-9,223,372,036,854,775,807  2,000,303   10.00 %

Eine alternative Technik, die Bitmanipulation verwendet, generiert keine wirklich zufälligen Zahlen. Diese Technik ruft Next() auf, zwei ganzzahlige Zahlen zu generieren, wobei links um 32 Bit und ORs zusammen verschoben werden. Diese Technik hat zwei Einschränkungen:

  1. Da Bit 31 das Vorzeichenbit ist, ist der Wert in Bit 31 der resultierenden langen Ganzzahl immer 0. Dies kann behoben werden, indem eine zufällige 0 oder 1 generiert wird, es um 31 Bit nach links verschoben und mit der ursprünglichen ganzzahligen Zufallszahl ausgelöst wird.

  2. Ernster, da die Wahrscheinlichkeit, dass der von 0 zurückgegebene Next() Wert 0 ist, gibt es nur wenige Zufallszahlen im Bereich 0x0-0x00000000FFFFFFFF.

Abrufen von Bytes in einem angegebenen Bereich

Mit den Überladungen der Next Methode können Sie den Bereich von Zufallszahlen angeben, die NextBytes Methode jedoch nicht. Im folgenden Beispiel wird eine NextBytes Methode implementiert, mit der Sie den Bereich der zurückgegebenen Bytes angeben können. Sie definiert eine Random2 Klasse, die von der Methode abgeleitet Random und überladen wird NextBytes .

using System;

public class Example3
{
    public static void Main()
    {
        Random2 rnd = new Random2();
        Byte[] bytes = new Byte[10000];
        int[] total = new int[101];
        rnd.NextBytes(bytes, 0, 101);

        // Calculate how many of each value we have.
        foreach (var value in bytes)
            total[value]++;

        // Display the results.
        for (int ctr = 0; ctr < total.Length; ctr++)
        {
            Console.Write("{0,3}: {1,-3}   ", ctr, total[ctr]);
            if ((ctr + 1) % 5 == 0) Console.WriteLine();
        }
    }
}

public class Random2 : Random
{
    public Random2() : base()
    { }

    public Random2(int seed) : base(seed)
    { }

    public void NextBytes(byte[] bytes, byte minValue, byte maxValue)
    {
        for (int ctr = bytes.GetLowerBound(0); ctr <= bytes.GetUpperBound(0); ctr++)
            bytes[ctr] = (byte)Next(minValue, maxValue);
    }
}
// The example displays output like the following:
//         0: 115     1: 119     2: 92      3: 98      4: 92
//         5: 102     6: 103     7: 84      8: 93      9: 116
//        10: 91     11: 98     12: 106    13: 91     14: 92
//        15: 101    16: 100    17: 96     18: 97     19: 100
//        20: 101    21: 106    22: 112    23: 82     24: 85
//        25: 102    26: 107    27: 98     28: 106    29: 102
//        30: 109    31: 108    32: 94     33: 101    34: 107
//        35: 101    36: 86     37: 100    38: 101    39: 102
//        40: 113    41: 95     42: 96     43: 89     44: 99
//        45: 81     46: 89     47: 105    48: 100    49: 85
//        50: 103    51: 103    52: 93     53: 89     54: 91
//        55: 97     56: 105    57: 97     58: 110    59: 86
//        60: 116    61: 94     62: 117    63: 98     64: 110
//        65: 93     66: 102    67: 100    68: 105    69: 83
//        70: 81     71: 97     72: 85     73: 70     74: 98
//        75: 100    76: 110    77: 114    78: 83     79: 90
//        80: 96     81: 112    82: 102    83: 102    84: 99
//        85: 81     86: 100    87: 93     88: 99     89: 118
//        90: 95     91: 124    92: 108    93: 96     94: 104
//        95: 106    96: 99     97: 99     98: 92     99: 99
//       100: 108
open System

type Random2() =
    inherit Random()

    member this.NextBytes(bytes: byte[], minValue: byte, maxValue: byte) =
        for i=bytes.GetLowerBound(0) to bytes.GetUpperBound(0) do
            bytes.[i] <- this.Next(int minValue, int maxValue) |> byte

let rnd = Random2()
let bytes = Array.zeroCreate 10000
let total = Array.zeroCreate 101
rnd.NextBytes(bytes, 0uy, 101uy)

// Calculate how many of each value we have.
for v in bytes do 
    total.[int v] <- total.[int v] + 1

// Display the results.
for i = 0 to total.Length - 1 do
    printf "%3i: %-3i   " i total.[i]
    if (i + 1) % 5 = 0 then printfn ""

// The example displays output like the following:
//         0: 115     1: 119     2: 92      3: 98      4: 92
//         5: 102     6: 103     7: 84      8: 93      9: 116
//        10: 91     11: 98     12: 106    13: 91     14: 92
//        15: 101    16: 100    17: 96     18: 97     19: 100
//        20: 101    21: 106    22: 112    23: 82     24: 85
//        25: 102    26: 107    27: 98     28: 106    29: 102
//        30: 109    31: 108    32: 94     33: 101    34: 107
//        35: 101    36: 86     37: 100    38: 101    39: 102
//        40: 113    41: 95     42: 96     43: 89     44: 99
//        45: 81     46: 89     47: 105    48: 100    49: 85
//        50: 103    51: 103    52: 93     53: 89     54: 91
//        55: 97     56: 105    57: 97     58: 110    59: 86
//        60: 116    61: 94     62: 117    63: 98     64: 110
//        65: 93     66: 102    67: 100    68: 105    69: 83
//        70: 81     71: 97     72: 85     73: 70     74: 98
//        75: 100    76: 110    77: 114    78: 83     79: 90
//        80: 96     81: 112    82: 102    83: 102    84: 99
//        85: 81     86: 100    87: 93     88: 99     89: 118
//        90: 95     91: 124    92: 108    93: 96     94: 104
//        95: 106    96: 99     97: 99     98: 92     99: 99
//       100: 108
Module Example4
    Public Sub Main()
        Dim rnd As New Random2()
        Dim bytes(9999) As Byte
        Dim total(100) As Integer
        rnd.NextBytes(bytes, 0, 101)

        ' Calculate how many of each value we have.
        For Each value In bytes
            total(value) += 1
        Next

        ' Display the results.
        For ctr As Integer = 0 To total.Length - 1
            Console.Write("{0,3}: {1,-3}   ", ctr, total(ctr))
            If (ctr + 1) Mod 5 = 0 Then Console.WriteLine()
        Next
    End Sub
End Module

Public Class Random2 : Inherits Random
   Public Sub New()
      MyBase.New()
   End Sub   

   Public Sub New(seed As Integer)
      MyBase.New(seed)
   End Sub

   Public Overloads Sub NextBytes(bytes() As Byte, 
                                  minValue As Byte, maxValue As Byte)
      For ctr As Integer = bytes.GetLowerbound(0) To bytes.GetUpperBound(0)
         bytes(ctr) = CByte(MyBase.Next(minValue, maxValue))
      Next
   End Sub
End Class 
' The example displays output like the following:
'         0: 115     1: 119     2: 92      3: 98      4: 92
'         5: 102     6: 103     7: 84      8: 93      9: 116
'        10: 91     11: 98     12: 106    13: 91     14: 92
'        15: 101    16: 100    17: 96     18: 97     19: 100
'        20: 101    21: 106    22: 112    23: 82     24: 85
'        25: 102    26: 107    27: 98     28: 106    29: 102
'        30: 109    31: 108    32: 94     33: 101    34: 107
'        35: 101    36: 86     37: 100    38: 101    39: 102
'        40: 113    41: 95     42: 96     43: 89     44: 99
'        45: 81     46: 89     47: 105    48: 100    49: 85
'        50: 103    51: 103    52: 93     53: 89     54: 91
'        55: 97     56: 105    57: 97     58: 110    59: 86
'        60: 116    61: 94     62: 117    63: 98     64: 110
'        65: 93     66: 102    67: 100    68: 105    69: 83
'        70: 81     71: 97     72: 85     73: 70     74: 98
'        75: 100    76: 110    77: 114    78: 83     79: 90
'        80: 96     81: 112    82: 102    83: 102    84: 99
'        85: 81     86: 100    87: 93     88: 99     89: 118
'        90: 95     91: 124    92: 108    93: 96     94: 104
'        95: 106    96: 99     97: 99     98: 92     99: 99
'       100: 108

Die NextBytes(Byte[], Byte, Byte) Methode umschließt einen Aufruf der Next(Int32, Int32) Methode und gibt den Minimalwert und einen wert größer als den Maximalwert (in diesem Fall 0 und 101) an, den wir im Bytearray zurückgeben möchten. Da wir sicher sind, dass die von der Next Methode zurückgegebenen ganzzahligen Werte innerhalb des Bereichs des Byte Datentyps liegen, können sie sicher (in C# und F#) umgewandelt oder (in Visual Basic) von ganzzahligen Zahlen in Byte konvertiert werden.

Abrufen eines Elements aus einem Array oder einer Sammlung nach dem Zufallsprinzip

Zufallszahlen dienen häufig als Indizes zum Abrufen von Werten aus Arrays oder Sammlungen. Um einen zufälligen Indexwert abzurufen, können Sie die Next(Int32, Int32) Methode aufrufen und die untere Grenze des Arrays als Wert des minValue Arguments verwenden und eine größer als die obere Grenze des Arrays als Wert des maxValue Arguments sein. Bei einem nullbasierten Array entspricht dies seiner Length Eigenschaft oder mindestens einem Wert, der von der Array.GetUpperBound Methode zurückgegeben wird. Im folgenden Beispiel wird der Name einer Stadt im USA zufällig aus einer Reihe von Städten abgerufen.

String[] cities = { "Atlanta", "Boston", "Chicago", "Detroit",
                    "Fort Wayne", "Greensboro", "Honolulu", "Indianapolis",
                    "Jersey City", "Kansas City", "Los Angeles",
                    "Milwaukee", "New York", "Omaha", "Philadelphia",
                    "Raleigh", "San Francisco", "Tulsa", "Washington" };
Random rnd = new Random();
int index = rnd.Next(0, cities.Length);
Console.WriteLine("Today's city of the day: {0}",
                  cities[index]);

// The example displays output like the following:
//   Today's city of the day: Honolulu
let cities = 
    [| "Atlanta"; "Boston"; "Chicago"; "Detroit";
       "Fort Wayne"; "Greensboro"; "Honolulu"; "Indianapolis";
       "Jersey City"; "Kansas City"; "Los Angeles";
       "Milwaukee"; "New York"; "Omaha"; "Philadelphia";
       "Raleigh"; "San Francisco"; "Tulsa"; "Washington" |]

let rnd = Random()

let index = rnd.Next(0,cities.Length)

printfn "Today's city of the day: %s" cities.[index]

// The example displays output like the following:
//   Today's city of the day: Honolulu
Module Example1
    Public Sub Main()
        Dim cities() As String = {"Atlanta", "Boston", "Chicago", "Detroit",
                                 "Fort Wayne", "Greensboro", "Honolulu", "Indianapolis",
                                 "Jersey City", "Kansas City", "Los Angeles",
                                 "Milwaukee", "New York", "Omaha", "Philadelphia",
                                 "Raleigh", "San Francisco", "Tulsa", "Washington"}
        Dim rnd As New Random()
        Dim index As Integer = rnd.Next(0, cities.Length)
        Console.WriteLine("Today's city of the day: {0}",
                        cities(index))
    End Sub
End Module
' The example displays output like the following:
'   Today's city of the day: Honolulu

Abrufen eines eindeutigen Elements aus einem Array oder einer Sammlung

Ein Zufallszahlengenerator kann immer doppelte Werte zurückgeben. Wenn der Zahlenbereich kleiner wird oder die Anzahl der generierten Werte größer wird, wächst die Wahrscheinlichkeit von Duplikaten. Wenn Zufallswerte eindeutig sein müssen, werden mehr Zahlen generiert, um Duplikate zu kompensieren, was zu zunehmend schlechter Leistung führt.

Für dieses Szenario gibt es eine Reihe von Techniken. Eine gängige Lösung besteht darin, ein Array oder eine Auflistung zu erstellen, die die abzurufenden Werte enthält, und ein paralleles Array, das zufällige Gleitkommazahlen enthält. Das zweite Array wird mit Zufallszahlen aufgefüllt, wenn das erste Array erstellt wird, und die Array.Sort(Array, Array) Methode wird verwendet, um das erste Array mithilfe der Werte im parallelen Array zu sortieren.

Wenn Sie beispielsweise ein Solitaire-Spiel entwickeln, sollten Sie sicherstellen, dass jedes Karte nur einmal verwendet wird. Anstatt Zufallszahlen zu generieren, um eine Karte abzurufen und nachzuverfolgen, ob diese Karte bereits behandelt wurde, können Sie ein paralleles Array von Zufallszahlen erstellen, mit denen die Deck sortiert werden kann. Nachdem der Foliensatz sortiert wurde, kann Ihre App einen Zeiger Standard, um den Index der nächsten Karte auf dem Deck anzugeben.

Dieser Ansatz wird anhand des folgenden Beispiels veranschaulicht. Es definiert eine Card Klasse, die eine spielige Karte und eine Dealer Klasse darstellt, die eine Reihe von shuffled Karte s behandelt. Der Dealer Klassenkonstruktor füllt zwei Arrays auf: ein deck Array mit Klassenbereich und das alle Karte im Deck darstellt; und ein lokales order Array, das dieselbe Anzahl von Elementen wie das deck Array aufweist und mit zufällig generierten Double Werten aufgefüllt wird. Die Array.Sort(Array, Array) Methode wird dann aufgerufen, um das deck Array basierend auf den Werten im order Array zu sortieren.

using System;

// A class that represents an individual card in a playing deck.
public class Card
{
    public Suit Suit;
    public FaceValue FaceValue;

    public override String ToString()
    {
        return String.Format("{0:F} of {1:F}", this.FaceValue, this.Suit);
    }
}

public enum Suit { Hearts, Diamonds, Spades, Clubs };

public enum FaceValue
{
    Ace = 1, Two, Three, Four, Five, Six,
    Seven, Eight, Nine, Ten, Jack, Queen,
    King
};

public class Dealer
{
    Random rnd;
    // A deck of cards, without Jokers.
    Card[] deck = new Card[52];
    // Parallel array for sorting cards.
    Double[] order = new Double[52];
    // A pointer to the next card to deal.
    int ptr = 0;
    // A flag to indicate the deck is used.
    bool mustReshuffle = false;

    public Dealer()
    {
        rnd = new Random();
        // Initialize the deck.
        int deckCtr = 0;
        foreach (var suit in Enum.GetValues(typeof(Suit)))
        {
            foreach (var faceValue in Enum.GetValues(typeof(FaceValue)))
            {
                Card card = new Card();
                card.Suit = (Suit)suit;
                card.FaceValue = (FaceValue)faceValue;
                deck[deckCtr] = card;
                deckCtr++;
            }
        }

        for (int ctr = 0; ctr < order.Length; ctr++)
            order[ctr] = rnd.NextDouble();

        Array.Sort(order, deck);
    }

    public Card[] Deal(int numberToDeal)
    {
        if (mustReshuffle)
        {
            Console.WriteLine("There are no cards left in the deck");
            return null;
        }

        Card[] cardsDealt = new Card[numberToDeal];
        for (int ctr = 0; ctr < numberToDeal; ctr++)
        {
            cardsDealt[ctr] = deck[ptr];
            ptr++;
            if (ptr == deck.Length)
                mustReshuffle = true;

            if (mustReshuffle & ctr < numberToDeal - 1)
            {
                Console.WriteLine("Can only deal the {0} cards remaining on the deck.",
                                  ctr + 1);
                return cardsDealt;
            }
        }
        return cardsDealt;
    }
}

public class Example17
{
    public static void Main()
    {
        Dealer dealer = new Dealer();
        ShowCards(dealer.Deal(20));
    }

    private static void ShowCards(Card[] cards)
    {
        foreach (var card in cards)
            if (card != null)
                Console.WriteLine("{0} of {1}", card.FaceValue, card.Suit);
    }
}
// The example displays output like the following:
//       Six of Diamonds
//       King of Clubs
//       Eight of Clubs
//       Seven of Clubs
//       Queen of Clubs
//       King of Hearts
//       Three of Spades
//       Ace of Clubs
//       Four of Hearts
//       Three of Diamonds
//       Nine of Diamonds
//       Two of Hearts
//       Ace of Hearts
//       Three of Hearts
//       Four of Spades
//       Eight of Hearts
//       Queen of Diamonds
//       Two of Clubs
//       Four of Diamonds
//       Jack of Hearts
open System

type Suit =
    | Clubs
    | Diamonds
    | Hearts
    | Spades

type Face =
    | Ace | Two | Three
    | Four | Five | Six
    | Seven | Eight | Nine
    | Ten | Jack | Queen | King

type Card = { Face: Face; Suit: Suit }

let suits = [ Clubs; Diamonds; Hearts; Spades ]
let faces = [ Ace; Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten; Jack; Queen; King ]

type Dealer() =
    let rnd = Random()
    let mutable pos = 0
    // Parallel array for sorting cards.
    let order = Array.init (suits.Length * faces.Length) (fun _ -> rnd.NextDouble() )
    // A deck of cards, without Jokers.
    let deck = [|
        for s in suits do
            for f in faces do
                { Face = f; Suit = s } |]
    // Shuffle the deck.
    do Array.Sort(order, deck)

    // Deal a number of cards from the deck, return None if failed
    member _.Deal(numberToDeal) : Card [] option = 
        if numberToDeal = 0 || pos = deck.Length then
            printfn "There are no cards left in the deck"
            None
        else 
            let cards = deck.[pos .. numberToDeal + pos - 1]
            if numberToDeal > deck.Length - pos then
                printfn "Can only deal the %i cards remaining on the deck." (deck.Length - pos)
            pos <- min (pos + numberToDeal) deck.Length
            Some cards

let showCards cards = 
    for card in cards do
        printfn $"{card.Face} of {card.Suit}"

let dealer = Dealer()

dealer.Deal 20
|> Option.iter showCards

// The example displays output like the following:
//       Six of Diamonds
//       King of Clubs
//       Eight of Clubs
//       Seven of Clubs
//       Queen of Clubs
//       King of Hearts
//       Three of Spades
//       Ace of Clubs
//       Four of Hearts
//       Three of Diamonds
//       Nine of Diamonds
//       Two of Hearts
//       Ace of Hearts
//       Three of Hearts
//       Four of Spades
//       Eight of Hearts
//       Queen of Diamonds
//       Two of Clubs
//       Four of Diamonds
//       Jack of Hearts
' A class that represents an individual card in a playing deck.
Public Class Card
   Public Suit As Suit
   Public FaceValue As FaceValue
   
   Public Overrides Function ToString() As String
      Return String.Format("{0:F} of {1:F}", Me.FaceValue, Me.Suit)
   End Function
End Class

Public Enum Suit As Integer
   Hearts = 0
   Diamonds = 1
   Spades = 2
   Clubs = 3
End Enum

Public Enum FaceValue As Integer
   Ace = 1
   Two = 2
   Three = 3
   Four = 4
   Five = 5
   Six = 6
   Seven = 7
   Eight = 8
   Nine = 9
   Ten = 10
   Jack = 11
   Queen = 12
   King = 13
End Enum

Public Class Dealer
   Dim rnd As Random
   ' A deck of cards, without Jokers.
   Dim deck(51) As Card
   ' Parallel array for sorting cards.
   Dim order(51) As Double
   ' A pointer to the next card to deal.
   Dim ptr As Integer = 0
   ' A flag to indicate the deck is used.
   Dim mustReshuffle As Boolean
   
   Public Sub New()
      rnd = New Random()
      ' Initialize the deck.
      Dim deckCtr As Integer = 0
      For Each Suit In [Enum].GetValues(GetType(Suit))
         For Each faceValue In [Enum].GetValues(GetType(FaceValue))
            Dim card As New Card()
            card.Suit = CType(Suit, Suit)
            card.FaceValue = CType(faceValue, FaceValue)
            deck(deckCtr) = card  
            deckCtr += 1
         Next
      Next
      For ctr As Integer = 0 To order.Length - 1
         order(ctr) = rnd.NextDouble()   
      Next   
      Array.Sort(order, deck)
   End Sub

   Public Function Deal(numberToDeal As Integer) As Card()
      If mustReshuffle Then
         Console.WriteLine("There are no cards left in the deck")
         Return Nothing
      End If
      
      Dim cardsDealt(numberToDeal - 1) As Card
      For ctr As Integer = 0 To numberToDeal - 1
         cardsDealt(ctr) = deck(ptr)
         ptr += 1
         If ptr = deck.Length Then 
            mustReshuffle = True
         End If
         If mustReshuffle And ctr < numberToDeal - 1
            Console.WriteLine("Can only deal the {0} cards remaining on the deck.", 
                              ctr + 1)
            Return cardsDealt
         End If
      Next
      Return cardsDealt
   End Function
End Class

Public Module Example
   Public Sub Main()
      Dim dealer As New Dealer()
      ShowCards(dealer.Deal(20))
   End Sub
   
   Private Sub ShowCards(cards() As Card)
      For Each card In cards
         If card IsNot Nothing Then _
            Console.WriteLine("{0} of {1}", card.FaceValue, card.Suit)
      Next
   End Sub
End Module
' The example displays output like the following:
'       Six of Diamonds
'       King of Clubs
'       Eight of Clubs
'       Seven of Clubs
'       Queen of Clubs
'       King of Hearts
'       Three of Spades
'       Ace of Clubs
'       Four of Hearts
'       Three of Diamonds
'       Nine of Diamonds
'       Two of Hearts
'       Ace of Hearts
'       Three of Hearts
'       Four of Spades
'       Eight of Hearts
'       Queen of Diamonds
'       Two of Clubs
'       Four of Diamonds
'       Jack of Hearts