System.Random-klasse
In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.
De Random klasse vertegenwoordigt een pseudo-willekeurige getalgenerator, een algoritme dat een reeks getallen produceert die voldoen aan bepaalde statistische vereisten voor willekeurigheid.
Pseudo-willekeurige getallen worden gekozen met gelijke waarschijnlijkheid uit een eindige set getallen. De gekozen getallen zijn niet volledig willekeurig omdat een wiskundig algoritme wordt gebruikt om ze te selecteren, maar ze zijn voldoende willekeurig voor praktische doeleinden. De implementatie van de Random klasse is gebaseerd op een gewijzigde versie van Donald E. Knuth's subtractive random number generator algoritme. Zie D. E. Knuth voor meer informatie. The Art of Computer Programming, Volume 2: Seminumerical Algorithms. Addison-Wesley, Reading, MA, derde editie, 1997.
Gebruik een van de statische methoden in de System.Security.Cryptography.RandomNumberGenerator klasse om een cryptografisch veilig willekeurig getal te genereren, zoals een willekeurig wachtwoord dat geschikt is voor het maken van een willekeurig wachtwoord.
Instantieer de generator voor willekeurige getallen
U maakt een instantie van de generator voor willekeurige getallen door een seed-waarde (een beginwaarde voor het pseudo-willekeurige generatie-algoritme) op te geven aan een Random klasseconstructor. U kunt de seed-waarde expliciet of impliciet opgeven:
- De Random(Int32) constructor gebruikt een expliciete seed-waarde die u opgeeft.
- De Random() constructor gebruikt de standaard seed-waarde. Dit is de meest voorkomende manier om de generator voor willekeurige getallen te instantiëren.
In .NET Framework is de standaard seed-waarde tijdafhankelijk. In .NET Core wordt de standaard seed-waarde geproduceerd door de thread-statische, pseudo-willekeurige getalgenerator.
Als hetzelfde zaad wordt gebruikt voor afzonderlijke Random objecten, genereren ze dezelfde reeks willekeurige getallen. Dit kan handig zijn voor het maken van een testpakket waarmee willekeurige waarden worden verwerkt of voor het opnieuw afspelen van games die hun gegevens afleiden uit willekeurige getallen. Houd er echter rekening mee dat Random objecten in processen die worden uitgevoerd onder verschillende versies van .NET Framework, verschillende reeks willekeurige getallen kunnen retourneren, zelfs als ze worden geïnstantieerd met identieke seed-waarden.
Als u verschillende reeksen willekeurige getallen wilt produceren, kunt u de tijdafhankelijk maken van de seed-waarde, waardoor een andere reeks wordt geproduceerd met elk nieuw exemplaar van Random. De geparameteriseerde Random(Int32) constructor kan een Int32 waarde nemen op basis van het aantal tikken in de huidige tijd, terwijl de parameterloze Random() constructor de systeemklok gebruikt om de seed-waarde te genereren. Alleen in .NET Framework, omdat de klok eindige resolutie heeft, maakt u echter alleen met behulp van de constructor zonder parameters verschillende Random objecten achter elkaar om willekeurige getalgeneratoren te maken die identieke reeksen willekeurige getallen produceren. In het volgende voorbeeld ziet u hoe twee Random objecten die naast elkaar worden geïnstantieerd in een .NET Framework-toepassing, een identieke reeks willekeurige getallen genereren. Op de meeste Windows-systemen Random hebben objecten die binnen 15 milliseconden van elkaar zijn gemaakt, waarschijnlijk identieke seed-waarden.
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
U kunt dit probleem voorkomen door één Random object te maken in plaats van meerdere objecten. Houd er rekening mee dat de Random
klasse in .NET Core deze beperking niet heeft.
Vermijd meerdere instantiëringen
In .NET Framework maakt het initialiseren van twee generatoren voor willekeurige getallen in een strakke lus of snelvolgorde twee generatoren voor willekeurige getallen die identieke reeksen willekeurige getallen kunnen produceren. In de meeste gevallen is dit niet de bedoeling van de ontwikkelaar en kan dit leiden tot prestatieproblemen, omdat het instantiëren en initialiseren van een generator voor willekeurige getallen een relatief duur proces is.
Om de prestaties te verbeteren en onbedoeld afzonderlijke generatoren voor willekeurige getallen te maken die identieke numerieke reeksen genereren, raden we u aan om één Random object te maken voor het genereren van veel willekeurige getallen in de loop van de tijd, in plaats van nieuwe Random objecten te maken om één willekeurig getal te genereren.
De Random klasse is echter niet thread-veilig. Als u methoden aanroept Random vanuit meerdere threads, volgt u de richtlijnen die in de volgende sectie worden besproken.
Schroefdraadveiligheid
In plaats van afzonderlijke Random objecten te instantiëren, raden we u aan om één Random exemplaar te maken om alle willekeurige getallen te genereren die nodig zijn voor uw app. Random Objecten zijn echter niet thread-veilig. Als uw app methoden aanroept Random vanuit meerdere threads, moet u een synchronisatieobject gebruiken om ervoor te zorgen dat slechts één thread tegelijkertijd toegang heeft tot de generator voor willekeurige getallen. Als u niet zeker weet dat het Random object op een threadveilige manier wordt geopend, wordt aangeroepen naar methoden die willekeurige getallen retourneren 0.
In het volgende voorbeeld worden de C# -vergrendelingsinstructie, de F# -vergrendelingsfunctie en de Visual Basic SyncLock-instructie gebruikt om ervoor te zorgen dat één generator voor willekeurige getallen wordt geopend door 11 threads op een thread-veilige manier. Elke thread genereert 2 miljoen willekeurige getallen, telt het aantal willekeurige getallen dat wordt gegenereerd en berekent de som en werkt vervolgens de totalen voor alle threads bij wanneer deze is uitgevoerd.
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: {totalCount:N0}");
Console.WriteLine($"Total sum of all random numbers: {totalValue:N2}");
Console.WriteLine($"Random number mean: {totalValue / totalCount:N4}");
}
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 {Thread.CurrentThread.Name} finished execution.");
Console.WriteLine($"Random numbers generated: {perThreadCtr:N0}");
Console.WriteLine($"Sum of random numbers: {perThreadTotal:N2}");
Console.WriteLine($"Random number mean: {perThreadTotal / perThreadCtr:N4}\n");
// Update overall totals.
lock (numericLock)
{
totalCount += perThreadCtr;
totalValue += perThreadTotal;
}
}
catch (OperationCanceledException e)
{
Console.WriteLine($"Corruption in Thread {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
Het voorbeeld zorgt voor thread-veiligheid op de volgende manieren:
- Het ThreadStaticAttribute kenmerk wordt gebruikt om thread-lokale variabelen te definiëren waarmee het totale aantal willekeurige getallen wordt bijgehouden dat wordt gegenereerd en de som voor elke thread.
- Een vergrendeling (de
lock
instructie in C#, delock
functie in F# en deSyncLock
instructie in Visual Basic) beveiligt de toegang tot de variabelen voor het totale aantal en de som van alle willekeurige getallen die zijn gegenereerd op alle threads. - Er wordt een semaphore (het CountdownEvent object) gebruikt om ervoor te zorgen dat de hoofdthreadblokken worden geblokkeerd totdat alle andere threads de uitvoering hebben voltooid.
- In het voorbeeld wordt gecontroleerd of de generator voor willekeurige getallen beschadigd is geraakt door te bepalen of twee opeenvolgende aanroepen naar methoden voor het genereren van willekeurige getallen 0 retourneren. Als er beschadiging wordt gedetecteerd, gebruikt het voorbeeld het CancellationTokenSource object om aan te geven dat alle threads moeten worden geannuleerd.
- Voordat u elk willekeurig getal genereert, controleert elke thread de status van het CancellationToken object. Als annulering wordt aangevraagd, roept het voorbeeld de CancellationToken.ThrowIfCancellationRequested methode aan om de thread te annuleren.
Het volgende voorbeeld is identiek aan het eerste, behalve dat er een Task object en een lambda-expressie worden gebruikt in plaats van Thread objecten.
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 {taskNo} finished execution.");
Console.WriteLine($"Random numbers generated: {taskCtr:N0}");
Console.WriteLine($"Sum of random numbers: {taskTotal:N2}");
Console.WriteLine($"Random number mean: {taskTotal / taskCtr:N4}\n");
// Update overall totals.
lock (numericLock)
{
totalCount += taskCtr;
totalValue += taskTotal;
}
},
token));
}
try
{
await Task.WhenAll(tasks.ToArray());
Console.WriteLine($"\nTotal random numbers generated: {totalCount:N0}");
Console.WriteLine($"Total sum of all random numbers: {totalValue:N2}");
Console.WriteLine($"Random number mean: {totalValue / totalCount:N4}");
}
catch (AggregateException e)
{
foreach (Exception inner in e.InnerExceptions)
{
TaskCanceledException canc = inner as TaskCanceledException;
if (canc != null)
Console.WriteLine($"Task #{canc.Task.Id} cancelled.");
else
Console.WriteLine($"Exception: {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
Het verschilt van het eerste voorbeeld op de volgende manieren:
- De variabelen voor het bijhouden van het aantal willekeurige getallen dat wordt gegenereerd en de som ervan in elke taak zijn lokaal voor de taak, dus u hoeft het ThreadStaticAttribute kenmerk niet te gebruiken.
- De statische Task.WaitAll methode wordt gebruikt om ervoor te zorgen dat de hoofdthread niet wordt voltooid voordat alle taken zijn voltooid. Het object is niet nodig CountdownEvent .
- De uitzondering die het gevolg is van het annuleren van taken, wordt in de Task.WaitAll methode weergegeven. In het vorige voorbeeld wordt deze verwerkt door elke thread.
Verschillende typen willekeurige getallen genereren
De generator voor willekeurige getallen biedt methoden waarmee u de volgende soorten willekeurige getallen kunt genereren:
Een reeks Byte waarden. U bepaalt het aantal bytewaarden door een matrix door te geven aan het aantal elementen dat u wilt laten terugkeren naar de NextBytes methode. In het volgende voorbeeld worden 20 bytes gegenereerd.
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
Eén geheel getal. U kunt kiezen of u een geheel getal van 0 tot een maximumwaarde (Int32.MaxValue -1) wilt aanroepen door de Next() methode aan te roepen, een geheel getal tussen 0 en een specifieke waarde door de Next(Int32) methode aan te roepen, of een geheel getal binnen een bereik met waarden door de methode aan te Next(Int32, Int32) roepen. In de geparameteriseerde overbelastingen is de opgegeven maximumwaarde exclusief; Dat wil gezegd: het werkelijke maximumaantal dat wordt gegenereerd, is één kleiner dan de opgegeven waarde.
In het volgende voorbeeld wordt de methode aangeroepen voor het Next(Int32, Int32) genereren van 10 willekeurige getallen tussen -10 en 10. Houd er rekening mee dat het tweede argument voor de methode de exclusieve bovengrens aangeeft van het bereik van willekeurige waarden die door de methode worden geretourneerd. Met andere woorden, het grootste gehele getal dat door de methode kan worden geretourneerd, is één kleiner dan deze waarde.
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
Een enkele drijvendekommawaarde van 0,0 tot minder dan 1,0 door de methode aan te NextDouble roepen. De exclusieve bovengrens van het willekeurige getal dat door de methode wordt geretourneerd, is 1, dus de werkelijke bovengrens is 0,9999999999999999978. In het volgende voorbeeld worden 10 willekeurige drijvendekommagetalnummers gegenereerd.
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
Belangrijk
Met de Next(Int32, Int32) methode kunt u het bereik van het geretourneerde willekeurige getal opgeven. maxValue
De parameter, waarmee het geretourneerde bovenste bereik wordt opgegeven, is echter een exclusieve, niet een inclusieve waarde. Dit betekent dat de methode-aanroep Next(0, 100)
een waarde retourneert tussen 0 en 99, en niet tussen 0 en 100.
U kunt de Random klasse ook gebruiken voor taken zoals het genereren van willekeurige Booleaanse waarden, het genereren van willekeurige drijvendekommawaarden in een opgegeven bereik, het genereren van willekeurige 64-bits gehele getallen en het ophalen van een uniek element uit een matrix of verzameling.
Uw eigen algoritme vervangen
U kunt uw eigen generator voor willekeurige getallen implementeren door de klasse over te Random nemen en uw algoritme voor het genereren van willekeurige getallen op te geven. Als u uw eigen algoritme wilt opgeven, moet u de Sample methode overschrijven, waarmee het algoritme voor het genereren van willekeurige getallen wordt geïmplementeerd. U moet ook de Next(), Next(Int32, Int32)en NextBytes methoden overschrijven om ervoor te zorgen dat ze uw overschreven Sample methode aanroepen. U hoeft de Next(Int32) en NextDouble methoden niet te overschrijven.
Zie de Sample referentiepagina voor een voorbeeld dat is afgeleid van de Random klasse en de standaardgenerator voor pseudo-willekeurige getallen wijzigt.
Dezelfde reeks willekeurige waarden ophalen
Soms wilt u dezelfde reeks willekeurige getallen genereren in softwaretestscenario's en bij het spelen van games. Door te testen met dezelfde reeks willekeurige getallen kunt u regressies detecteren en opgeloste fouten bevestigen. Door dezelfde reeks willekeurige getallen in games te gebruiken, kunt u eerdere games opnieuw afspelen.
U kunt dezelfde reeks willekeurige getallen genereren door dezelfde seed-waarde op te geven aan de Random(Int32) constructor. De seed-waarde biedt een beginwaarde voor het pseudo-willekeurig genereren van getallen. In het volgende voorbeeld wordt 100100 gebruikt als een willekeurige seed-waarde om het Random object te instantiëren, worden 20 willekeurige drijvendekommawaarden weergegeven en blijft de seed-waarde behouden. Vervolgens wordt de seed-waarde hersteld, wordt een nieuwe generator voor willekeurige getallen geïnstitueert en worden dezelfde 20 willekeurige drijvendekommawaarden weergegeven. Houd er rekening mee dat het voorbeeld verschillende reeksen willekeurige getallen kan produceren als deze worden uitgevoerd op verschillende versies van .NET.
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
Unieke reeksen willekeurige getallen ophalen
Als u verschillende seed-waarden opgeeft aan exemplaren van de Random klasse, zorgt u ervoor dat elke generator voor willekeurige getallen een andere reeks waarden produceert. U kunt een seed-waarde expliciet opgeven door de Random(Int32) constructor aan te roepen of impliciet door de Random() constructor aan te roepen. De meeste ontwikkelaars noemen de parameterloze constructor, die gebruikmaakt van de systeemklok. In het volgende voorbeeld wordt deze methode gebruikt om twee Random exemplaren te instantiëren. Elk exemplaar geeft een reeks van 10 willekeurige gehele getallen weer.
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($" {rnd1.Next()}");
Console.WriteLine("\nThe second random number generator:");
for (int ctr = 1; ctr <= 10; ctr++)
Console.WriteLine($" {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
Vanwege de eindige resolutie detecteert de systeemklok echter geen tijdverschillen die kleiner zijn dan ongeveer 15 milliseconden. Als uw code de Random() overbelasting van .NET Framework aanroept om twee Random objecten achter elkaar te instantiëren, kunt u de objecten per ongeluk identieke seed-waarden verstrekken. (De Random klasse in .NET Core heeft deze beperking niet.) Als u dit in het vorige voorbeeld wilt zien, markeert u de aanroep van de Thread.Sleep methode als commentaar en compileert u het voorbeeld en voert u het opnieuw uit.
Om te voorkomen dat dit gebeurt, raden we u aan om één Random object te instantiëren in plaats van meerdere objecten. Aangezien Random thread echter niet veilig is, moet u een synchronisatieapparaat gebruiken als u toegang hebt tot een Random exemplaar vanuit meerdere threads. Zie de sectie Threadveiligheid voor meer informatie. U kunt ook een vertragingsmechanisme gebruiken, zoals de Sleep methode die in het vorige voorbeeld wordt gebruikt, om ervoor te zorgen dat de instantiëringen meer dan 15 milliseconden uit elkaar komen.
Gehele getallen in een opgegeven bereik ophalen
U kunt gehele getallen in een opgegeven bereik ophalen door de Next(Int32, Int32) methode aan te roepen, zodat u zowel de onder- als de bovengrens kunt opgeven van de getallen die u wilt laten retourneren door de generator voor willekeurige getallen. De bovengrens is een exclusieve, niet een inclusieve waarde. Dat wil gezegd, het is niet opgenomen in het bereik van waarden dat door de methode wordt geretourneerd. In het volgende voorbeeld wordt deze methode gebruikt om willekeurige gehele getallen tussen -10 en 10 te genereren. Houd er rekening mee dat hiermee 11 wordt opgegeven, die één groter is dan de gewenste waarde, als de waarde van het maxValue
argument in de methode-aanroep.
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
Gehele getallen ophalen met een opgegeven aantal cijfers
U kunt de Next(Int32, Int32) methode aanroepen om nummers op te halen met een opgegeven aantal cijfers. Als u bijvoorbeeld getallen wilt ophalen met vier cijfers (dat wil gezegd, getallen die variëren van 1000 tot 9999), roept u de Next(Int32, Int32) methode aan met een minValue
waarde van 1000 en een maxValue
waarde van 10000, zoals in het volgende voorbeeld wordt weergegeven.
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
Waarden voor drijvende komma ophalen in een opgegeven bereik
De NextDouble methode retourneert willekeurige drijvende-kommawaarden die variëren van 0 tot minder dan 1. U wilt echter vaak willekeurige waarden genereren in een ander bereik.
Als het interval tussen de minimum- en maximumwaarde 1 is, kunt u het verschil tussen het gewenste begininterval en 0 toevoegen aan het getal dat door de NextDouble methode wordt geretourneerd. In het volgende voorbeeld wordt dit uitgevoerd om 10 willekeurige getallen tussen -1 en 0 te genereren.
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
Als u willekeurige drijvendekommagetalnummers wilt genereren waarvan de ondergrens 0 is, maar bovengrens groter is dan 1 (of, in het geval van negatieve getallen, waarvan de ondergrens kleiner is dan -1 en bovengrens 0 is), vermenigvuldigt u het willekeurige getal met de niet-nulgrens. In het volgende voorbeeld wordt dit uitgevoerd om 20 miljoen willekeurige drijvendekommanummers te genereren die variëren van 0 tot Int64.MaxValue. In dit venster wordt ook de verdeling weergegeven van de willekeurige waarden die door de methode zijn gegenereerd.
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 %
Gebruik de volgende formule om willekeurige drijvendekommagetalnummers te genereren tussen twee willekeurige waarden, zoals de Next(Int32, Int32) methode doet voor gehele getallen:
Random.NextDouble() * (maxValue - minValue) + minValue
In het volgende voorbeeld worden 1 miljoen willekeurige getallen gegenereerd die variëren van 10,0 tot 11,0 en hun verdeling weergeven.
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 %)
Willekeurige Booleaanse waarden genereren
De Random klasse biedt geen methoden waarmee waarden worden gegenereerd Boolean . U kunt echter uw eigen klasse of methode definiëren om dat te doen. In het volgende voorbeeld wordt een klasse, BooleanGenerator
met één methode, NextBoolean
gedefinieerd. In de BooleanGenerator
klasse wordt een Random object opgeslagen als een privévariabele. De NextBoolean
methode roept de methode aan Random.Next(Int32, Int32) en geeft het resultaat door aan de Convert.ToBoolean(Int32) methode. Houd er rekening mee dat 2 wordt gebruikt als argument om de bovengrens van het willekeurige getal op te geven. Omdat dit een exclusieve waarde is, retourneert de methodeaanroep 0 of 1.
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 %)
In plaats van een afzonderlijke klasse te maken om willekeurige Boolean waarden te genereren, kan in het voorbeeld slechts één methode zijn gedefinieerd. In dat geval moet het Random object echter zijn gedefinieerd als een variabele op klasseniveau om te voorkomen dat er een nieuw Random exemplaar wordt geïnstrigeerd in elke methode-aanroep. In Visual Basic kan het willekeurige exemplaar worden gedefinieerd als een statische variabele in de NextBoolean
methode. In het volgende voorbeeld ziet u een implementatie.
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 %)
Willekeurige 64-bits gehele getallen genereren
De overbelasting van de Next methode retourneert 32-bits gehele getallen. In sommige gevallen wilt u echter mogelijk werken met 64-bits gehele getallen. U kunt dit als volgt doen:
Roep de NextDouble methode aan om een drijvende kommawaarde met dubbele precisie op te halen.
Vermenigvuldig die waarde met Int64.MaxValue.
In het volgende voorbeeld wordt deze techniek gebruikt om 20 miljoen willekeurige lange gehele getallen te genereren en deze in 10 gelijke groepen te categoriseren. Vervolgens wordt de verdeling van de willekeurige getallen geëvalueerd door het getal in elke groep van 0 tot en met 0 te Int64.MaxValuetellen. Zoals de uitvoer uit het voorbeeld laat zien, worden de getallen gelijkmatig verdeeld over het bereik van een lang geheel getal.
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 %
Een alternatieve techniek die bitmanipulatie gebruikt, genereert geen echt willekeurige getallen. Deze techniek roept aan Next() om twee gehele getallen te genereren, naar links verschuift één voor 32 bits en OR's samen. Deze techniek heeft twee beperkingen:
Omdat bit 31 de tekenbit is, is de waarde in bit 31 van het resulterende lange gehele getal altijd 0. Dit kan worden verholpen door een willekeurige 0 of 1 te genereren, deze 31 bits naar links te verplaatsen en door deze te ORing met het oorspronkelijke willekeurige lange gehele getal.
Serieuser, omdat de kans dat de waarde die wordt geretourneerd Next() 0 is, er weinig zijn als er willekeurige getallen in het bereik 0x0-0x00000000FFFFFFFF.
Bytes in een opgegeven bereik ophalen
Met de overbelasting van de Next methode kunt u het bereik van willekeurige getallen opgeven, maar de NextBytes methode niet. In het volgende voorbeeld wordt een NextBytes
methode geïmplementeerd waarmee u het bereik van de geretourneerde bytes kunt opgeven. Het definieert een Random2
klasse die is afgeleid van Random en overbelast de NextBytes
methode.
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
De NextBytes(Byte[], Byte, Byte)
methode verpakt een aanroep naar de Next(Int32, Int32) methode en geeft de minimumwaarde op en één groter dan de maximumwaarde (in dit geval 0 en 101) die we in de bytematrix willen retourneren. Omdat we er zeker van zijn dat de gehele getallen die door de Next methode worden geretourneerd zich binnen het gegevensbereik van het Byte gegevenstype bevinden, kunnen we ze veilig casten (in C# en F#) of ze (in Visual Basic) converteren van gehele getallen naar bytes.
Een element ophalen uit een matrix of verzameling willekeurig
Willekeurige getallen fungeren vaak als indexen om waarden op te halen uit matrices of verzamelingen. Als u een willekeurige indexwaarde wilt ophalen, kunt u de Next(Int32, Int32) methode aanroepen en de ondergrens van de matrix gebruiken als de waarde van het argument en minValue
één groter dan de bovengrens van de matrix als de waarde van het maxValue
argument. Voor een matrix op basis van nul is dit gelijk aan Length de eigenschap of één groter dan de waarde die door de Array.GetUpperBound methode wordt geretourneerd. In het volgende voorbeeld wordt willekeurig de naam van een stad in de Verenigde Staten opgehaald uit een matrix met steden.
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: {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
Een uniek element ophalen uit een matrix of verzameling
Een generator voor willekeurige getallen kan altijd dubbele waarden retourneren. Naarmate het bereik van getallen kleiner wordt of het aantal gegenereerde waarden groter wordt, neemt de kans op duplicaten toe. Als willekeurige waarden uniek moeten zijn, worden er meer getallen gegenereerd om dubbele waarden te compenseren, wat resulteert in steeds slechtere prestaties.
Er zijn een aantal technieken om dit scenario af te handelen. Een veelvoorkomende oplossing is het maken van een matrix of verzameling die de waarden bevat die moeten worden opgehaald en een parallelle matrix die willekeurige drijvendekommanummers bevat. De tweede matrix wordt gevuld met willekeurige getallen op het moment dat de eerste matrix wordt gemaakt en de Array.Sort(Array, Array) methode wordt gebruikt om de eerste matrix te sorteren met behulp van de waarden in de parallelle matrix.
Als u bijvoorbeeld een Solitaire-spel ontwikkelt, wilt u ervoor zorgen dat elke kaart maar één keer wordt gebruikt. In plaats van willekeurige getallen te genereren om een kaart op te halen en bij te houden of die kaart al is behandeld, kunt u een parallelle matrix met willekeurige getallen maken die kunnen worden gebruikt om de deck te sorteren. Zodra het dek is gesorteerd, kan uw app een aanwijzer onderhouden om de index van de volgende kaart op het dek aan te geven.
In het volgende voorbeeld ziet u deze benadering. Hiermee wordt een Card
klasse gedefinieerd die een speelkaart vertegenwoordigt en een Dealer
klasse die een stapel kaarten in willekeurige volgorde behandelt. De Dealer
klasseconstructor vult twee matrices in: een deck
matrix met klassebereik en die alle kaarten in de stapel vertegenwoordigt; en een lokale order
matrix met hetzelfde aantal elementen als de deck
matrix en wordt gevuld met willekeurig gegenereerde Double waarden. De Array.Sort(Array, Array) methode wordt vervolgens aangeroepen om de deck
matrix te sorteren op basis van de waarden in de order
matrix.
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 {ctr + 1} cards remaining on the deck.");
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($"{card.FaceValue} of {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