Random Clase
Definición
Importante
Parte de la información hace referencia a la versión preliminar del producto, que puede haberse modificado sustancialmente antes de lanzar la versión definitiva. Microsoft no otorga ninguna garantía, explícita o implícita, con respecto a la información proporcionada aquí.
Representa un generador de números seudoaleatorios, que es un algoritmo que genera una secuencia de números que cumplen determinados requisitos estadísticos de aleatoriedad.
public ref class Random
public class Random
[System.Serializable]
public class Random
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class Random
type Random = class
[<System.Serializable>]
type Random = class
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type Random = class
Public Class Random
- Herencia
-
Random
- Atributos
Ejemplos
En el ejemplo siguiente se crea un único generador de números aleatorios y se llama a sus NextBytesmétodos , Nexty NextDouble para generar secuencias de números aleatorios dentro de diferentes intervalos.
using namespace System;
void main()
{
// Instantiate random number generator using system-supplied value as seed.
Random^ rand = gcnew Random();
// Generate and display 5 random byte (integer) values.
array<Byte>^ bytes = gcnew array<Byte>(4);
rand->NextBytes(bytes);
Console::WriteLine("Five random byte values:");
for each (Byte byteValue in bytes)
Console::Write("{0, 5}", byteValue);
Console::WriteLine();
// Generate and display 5 random integers.
Console::WriteLine("Five random integer values:");
for (int ctr = 0; ctr <= 4; ctr++)
Console::Write("{0,15:N0}", rand->Next());
Console::WriteLine();
// Generate and display 5 random integers between 0 and 100.//
Console::WriteLine("Five random integers between 0 and 100:");
for (int ctr = 0; ctr <= 4; ctr++)
Console::Write("{0,8:N0}", rand->Next(101));
Console::WriteLine();
// Generate and display 5 random integers from 50 to 100.
Console::WriteLine("Five random integers between 50 and 100:");
for (int ctr = 0; ctr <= 4; ctr++)
Console::Write("{0,8:N0}", rand->Next(50, 101));
Console::WriteLine();
// Generate and display 5 random floating point values from 0 to 1.
Console::WriteLine("Five Doubles.");
for (int ctr = 0; ctr <= 4; ctr++)
Console::Write("{0,8:N3}", rand->NextDouble());
Console::WriteLine();
// Generate and display 5 random floating point values from 0 to 5.
Console::WriteLine("Five Doubles between 0 and 5.");
for (int ctr = 0; ctr <= 4; ctr++)
Console::Write("{0,8:N3}", rand->NextDouble() * 5);
}
// The example displays output like the following:
// Five random byte values:
// 194 185 239 54 116
// Five random integer values:
// 507,353,531 1,509,532,693 2,125,074,958 1,409,512,757 652,767,128
// Five random integers between 0 and 100:
// 16 78 94 79 52
// Five random integers between 50 and 100:
// 56 66 96 60 65
// Five Doubles.
// 0.943 0.108 0.744 0.563 0.415
// Five Doubles between 0 and 5.
// 2.934 3.130 0.292 1.432 4.369
// Instantiate random number generator using system-supplied value as seed.
var rand = new Random();
// Generate and display 5 random byte (integer) values.
var bytes = new byte[5];
rand.NextBytes(bytes);
Console.WriteLine("Five random byte values:");
foreach (byte byteValue in bytes)
Console.Write("{0, 5}", byteValue);
Console.WriteLine();
// Generate and display 5 random integers.
Console.WriteLine("Five random integer values:");
for (int ctr = 0; ctr <= 4; ctr++)
Console.Write("{0,15:N0}", rand.Next());
Console.WriteLine();
// Generate and display 5 random integers between 0 and 100.
Console.WriteLine("Five random integers between 0 and 100:");
for (int ctr = 0; ctr <= 4; ctr++)
Console.Write("{0,8:N0}", rand.Next(101));
Console.WriteLine();
// Generate and display 5 random integers from 50 to 100.
Console.WriteLine("Five random integers between 50 and 100:");
for (int ctr = 0; ctr <= 4; ctr++)
Console.Write("{0,8:N0}", rand.Next(50, 101));
Console.WriteLine();
// Generate and display 5 random floating point values from 0 to 1.
Console.WriteLine("Five Doubles.");
for (int ctr = 0; ctr <= 4; ctr++)
Console.Write("{0,8:N3}", rand.NextDouble());
Console.WriteLine();
// Generate and display 5 random floating point values from 0 to 5.
Console.WriteLine("Five Doubles between 0 and 5.");
for (int ctr = 0; ctr <= 4; ctr++)
Console.Write("{0,8:N3}", rand.NextDouble() * 5);
// The example displays output like the following:
// Five random byte values:
// 194 185 239 54 116
// Five random integer values:
// 507,353,531 1,509,532,693 2,125,074,958 1,409,512,757 652,767,128
// Five random integers between 0 and 100:
// 16 78 94 79 52
// Five random integers between 50 and 100:
// 56 66 96 60 65
// Five Doubles.
// 0.943 0.108 0.744 0.563 0.415
// Five Doubles between 0 and 5.
// 2.934 3.130 0.292 1.432 4.369
// Instantiate random number generator using system-supplied value as seed.
let rand = Random()
// Generate and display 5 random byte (integer) values.
let bytes = Array.zeroCreate 5
rand.NextBytes bytes
printfn "Five random byte values:"
for byte in bytes do
printf "%5i" byte
printfn ""
// Generate and display 5 random integers.
printfn "Five random integer values:"
for _ = 0 to 4 do
printf $"{rand.Next(),15:N0}"
printfn ""
// Generate and display 5 random integers between 0 and 100.
printfn "Five random integers between 0 and 100:"
for _ = 0 to 4 do
printf $"{rand.Next 101,8:N0}"
printfn ""
// Generate and display 5 random integers from 50 to 100.
printfn "Five random integers between 50 and 100:"
for _ = 0 to 4 do
printf $"{rand.Next(50, 101),8:N0}"
printfn ""
// Generate and display 5 random floating point values from 0 to 1.
printfn "Five Doubles."
for _ = 0 to 4 do
printf $"{rand.NextDouble(),8:N3}"
printfn ""
// Generate and display 5 random floating point values from 0 to 5.
printfn "Five Doubles between 0 and 5."
for _ = 0 to 4 do
printf $"{rand.NextDouble() * 5.0,8:N3}"
// The example displays output like the following:
// Five random byte values:
// 194 185 239 54 116
// Five random integer values:
// 507,353,531 1,509,532,693 2,125,074,958 1,409,512,757 652,767,128
// Five random integers between 0 and 100:
// 16 78 94 79 52
// Five random integers between 50 and 100:
// 56 66 96 60 65
// Five Doubles.
// 0.943 0.108 0.744 0.563 0.415
// Five Doubles between 0 and 5.
// 2.934 3.130 0.292 1.432 4.369
Module Example
Public Sub Main()
' Instantiate random number generator using system-supplied value as seed.
Dim rand As New Random()
' Generate and display 5 random byte (integer) values.
Dim bytes(4) As Byte
rand.NextBytes(bytes)
Console.WriteLine("Five random byte values:")
For Each byteValue As Byte In bytes
Console.Write("{0, 5}", byteValue)
Next
Console.WriteLine()
' Generate and display 5 random integers.
Console.WriteLine("Five random integer values:")
For ctr As Integer = 0 To 4
Console.Write("{0,15:N0}", rand.Next)
Next
Console.WriteLine()
' Generate and display 5 random integers between 0 and 100.'
Console.WriteLine("Five random integers between 0 and 100:")
For ctr As Integer = 0 To 4
Console.Write("{0,8:N0}", rand.Next(101))
Next
Console.WriteLine()
' Generate and display 5 random integers from 50 to 100.
Console.WriteLine("Five random integers between 50 and 100:")
For ctr As Integer = 0 To 4
Console.Write("{0,8:N0}", rand.Next(50, 101))
Next
Console.WriteLine()
' Generate and display 5 random floating point values from 0 to 1.
Console.WriteLine("Five Doubles.")
For ctr As Integer = 0 To 4
Console.Write("{0,8:N3}", rand.NextDouble())
Next
Console.WriteLine()
' Generate and display 5 random floating point values from 0 to 5.
Console.WriteLine("Five Doubles between 0 and 5.")
For ctr As Integer = 0 To 4
Console.Write("{0,8:N3}", rand.NextDouble() * 5)
Next
End Sub
End Module
' The example displays output like the following:
' Five random byte values:
' 194 185 239 54 116
' Five random integer values:
' 507,353,531 1,509,532,693 2,125,074,958 1,409,512,757 652,767,128
' Five random integers between 0 and 100:
' 16 78 94 79 52
' Five random integers between 50 and 100:
' 56 66 96 60 65
' Five Doubles.
' 0.943 0.108 0.744 0.563 0.415
' Five Doubles between 0 and 5.
' 2.934 3.130 0.292 1.432 4.369
En el ejemplo siguiente se genera un entero aleatorio que usa como índice para recuperar un valor de cadena de una matriz.
using namespace System;
void main()
{
Random^ rnd = gcnew Random();
array<String^>^ malePetNames = { "Rufus", "Bear", "Dakota", "Fido",
"Vanya", "Samuel", "Koani", "Volodya",
"Prince", "Yiska" };
array<String^>^ femalePetNames = { "Maggie", "Penny", "Saya", "Princess",
"Abby", "Laila", "Sadie", "Olivia",
"Starlight", "Talla" };
// Generate random indexes for pet names.
int mIndex = rnd->Next(malePetNames->Length);
int fIndex = rnd->Next(femalePetNames->Length);
// Display the result.
Console::WriteLine("Suggested pet name of the day: ");
Console::WriteLine(" For a male: {0}", malePetNames[mIndex]);
Console::WriteLine(" For a female: {0}", femalePetNames[fIndex]);
}
// The example displays output similar to the following:
// Suggested pet name of the day:
// For a male: Koani
// For a female: Maggie
Random rnd = new Random();
string[] malePetNames = { "Rufus", "Bear", "Dakota", "Fido",
"Vanya", "Samuel", "Koani", "Volodya",
"Prince", "Yiska" };
string[] femalePetNames = { "Maggie", "Penny", "Saya", "Princess",
"Abby", "Laila", "Sadie", "Olivia",
"Starlight", "Talla" };
// Generate random indexes for pet names.
int mIndex = rnd.Next(malePetNames.Length);
int fIndex = rnd.Next(femalePetNames.Length);
// Display the result.
Console.WriteLine("Suggested pet name of the day: ");
Console.WriteLine(" For a male: {0}", malePetNames[mIndex]);
Console.WriteLine(" For a female: {0}", femalePetNames[fIndex]);
// The example displays output similar to the following:
// Suggested pet name of the day:
// For a male: Koani
// For a female: Maggie
let rnd = Random()
let malePetNames =
[| "Rufus"; "Bear"; "Dakota"; "Fido";
"Vanya"; "Samuel"; "Koani"; "Volodya";
"Prince"; "Yiska" |]
let femalePetNames =
[| "Maggie"; "Penny"; "Saya"; "Princess";
"Abby"; "Laila"; "Sadie"; "Olivia";
"Starlight"; "Talla" |]
// Generate random indexes for pet names.
let mIndex = rnd.Next malePetNames.Length
let fIndex = rnd.Next femalePetNames.Length
// Display the result.
printfn "Suggested pet name of the day: "
printfn " For a male: %s" malePetNames.[mIndex]
printfn " For a female: %s" femalePetNames.[fIndex]
// The example displays output similar to the following:
// Suggested pet name of the day:
// For a male: Koani
// For a female: Maggie
Module Example
Public Sub Main()
Dim rnd As New Random()
Dim malePetNames() As String = { "Rufus", "Bear", "Dakota", "Fido",
"Vanya", "Samuel", "Koani", "Volodya",
"Prince", "Yiska" }
Dim femalePetNames() As String = { "Maggie", "Penny", "Saya", "Princess",
"Abby", "Laila", "Sadie", "Olivia",
"Starlight", "Talla" }
' Generate random indexes for pet names.
Dim mIndex As Integer = rnd.Next(malePetNames.Length)
Dim fIndex As Integer = rnd.Next(femalePetNames.Length)
' Display the result.
Console.WriteLine("Suggested pet name of the day: ")
Console.WriteLine(" For a male: {0}", malePetNames(mIndex))
Console.WriteLine(" For a female: {0}", femalePetNames(fIndex))
End Sub
End Module
' The example displays output similar to the following:
' Suggested pet name of the day:
' For a male: Koani
' For a female: Maggie
Comentarios
Los números pseudoaleatorios se eligen con la misma probabilidad de un conjunto finito de números. Los números elegidos no son completamente aleatorios porque se usa un algoritmo matemático para seleccionarlos, pero son suficientemente aleatorios para fines prácticos. La implementación actual de la Random clase se basa en una versión modificada del algoritmo generador de números aleatorios resta de Donald E. Knuth. Para obtener más información, vea D. E. Knuth. El arte de la programación informática, volumen 2: algoritmos seminuméricos. Addison-Wesley, Reading, MA, tercera edición, 1997.
Para generar un número aleatorio criptográficomente seguro, como uno adecuado para crear una contraseña aleatoria, use la RNGCryptoServiceProvider clase o derive una clase de System.Security.Cryptography.RandomNumberGenerator.
En este tema:
Creación de instancias del generador de números aleatorios
Evitar varias instancias
La clase System.Random y la seguridad de subprocesos
Generación de diferentes tipos de números aleatorios
Sustituir su propio algoritmo
¿Cómo se usa System.Random para...
Recuperar la misma secuencia de valores aleatorios
Recuperación de secuencias únicas de valores aleatorios
Recuperar enteros en un intervalo especificado
Recuperar enteros con un número especificado de dígitos
Recuperar valores de punto flotante en un intervalo especificado
Generación de valores booleanos aleatorios
Generar enteros de 64 bits aleatorios
Recuperar bytes en un intervalo especificado
Recuperar un elemento de una matriz o colección de forma aleatoria
Recuperar un elemento único de una matriz o colección
Creación de instancias del generador de números aleatorios
Cree una instancia del generador de números aleatorios proporcionando un valor de inicialización (un valor inicial para el algoritmo de generación de números pseudoaleatorios) en un Random constructor de clase. Puede proporcionar el valor de inicialización explícita o implícitamente:
El Random(Int32) constructor usa un valor de inicialización explícito que se proporciona.
El Random() constructor usa el valor de inicialización predeterminado. Esta es la forma más común de crear instancias del generador de números aleatorios.
En .NET Framework, el valor de inicialización predeterminado depende del tiempo. En .NET Core, el generador de números pseudoaleatorios estáticos de subprocesos genera el valor de inicialización predeterminado.
Si se usa la misma inicialización para objetos independientes Random , generarán la misma serie de números aleatorios. Esto puede ser útil para crear un conjunto de pruebas que procese valores aleatorios o para reproducir juegos que deriven sus datos de números aleatorios. Sin embargo, tenga en cuenta que los objetos de los procesos que Random se ejecutan en versiones diferentes de .NET Framework pueden devolver diferentes series de números aleatorios, incluso si se crean instancias con valores de inicialización idénticos.
Para generar diferentes secuencias de números aleatorios, puede hacer que el valor de inicialización dependa del tiempo, lo que genera una serie diferente con cada nueva instancia de Random. El constructor con parámetros puede tomar un Int32 valor basado en el número de tics en la hora actual, mientras que el constructor sin Random() parámetros Random(Int32) usa el reloj del sistema para generar su valor de inicialización. Sin embargo, solo en .NET Framework, dado que el reloj tiene una resolución finita, el uso del constructor sin parámetros para crear objetos diferentes Random en sucesión cercana crea generadores de números aleatorios que producen secuencias idénticas de números aleatorios. En el ejemplo siguiente se muestra cómo se crean instancias de dos Random objetos en una sucesión cercana en una aplicación de .NET Framework que generan una serie idéntica de números aleatorios. En la mayoría de los sistemas Windows, Random es probable que los objetos creados en 15 milisegundos entre sí tengan valores de inicialización idénticos.
using namespace System;
void main()
{
array<Byte>^ bytes1 = gcnew array<Byte>(100);
array<Byte>^ bytes2 = gcnew array<Byte>(100);
Random^ rnd1 = gcnew Random();
Random^ rnd2 = gcnew 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
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
Para evitar este problema, cree un único Random objeto en lugar de varios objetos. Tenga en cuenta que la Random
clase de .NET Core no tiene esta limitación.
Evitar varias instancias
En .NET Framework, inicializar dos generadores de números aleatorios en un bucle ajustado o en sucesión rápida crea dos generadores de números aleatorios que pueden producir secuencias idénticas de números aleatorios. En la mayoría de los casos, esto no es la intención del desarrollador y puede dar lugar a problemas de rendimiento, ya que crear instancias e inicializar un generador de números aleatorios es un proceso relativamente costoso.
Tanto para mejorar el rendimiento como para evitar crear accidentalmente generadores de números aleatorios independientes que generen secuencias numéricas idénticas, se recomienda crear un Random objeto para generar muchos números aleatorios a lo largo del tiempo, en lugar de crear nuevos Random objetos para generar un número aleatorio.
Sin embargo, la Random clase no es segura para subprocesos. Si llama a Random métodos desde varios subprocesos, siga las instrucciones que se describen en la sección siguiente.
La clase System.Random y la seguridad de subprocesos
En lugar de crear instancias de objetos individuales Random , se recomienda crear una sola Random instancia para generar todos los números aleatorios necesarios para la aplicación. Sin embargo, Random los objetos no son seguros para subprocesos. Si la aplicación llama a Random métodos desde varios subprocesos, debe usar un objeto de sincronización para asegurarse de que solo un subproceso pueda acceder al generador de números aleatorios a la vez. Si no garantiza que se tenga acceso al Random objeto de forma segura para subprocesos, las llamadas a métodos que devuelven números aleatorios devuelven 0.
En el ejemplo siguiente se usa la instrucción lock de C#, la función de bloqueo de F# y la instrucción SyncLock de Visual Basic para asegurarse de que 11 subprocesos acceden a un único generador de números aleatorios de una manera segura para subprocesos. Cada subproceso genera 2 millones de números aleatorios, cuenta el número de números aleatorios generados y calcula su suma y, a continuación, actualiza los totales de todos los subprocesos cuando termina de ejecutarse.
using namespace System;
using namespace System::Threading;
ref class Example
{
private:
[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;
static Object^ numericLock;
static Random^ rand;
double totalValue = 0.0;
int totalCount = 0;
public:
Example()
{
rand = gcnew Random();
randLock = gcnew Object();
numericLock = gcnew Object();
countdown = gcnew CountdownEvent(1);
source = gcnew CancellationTokenSource();
}
void Execute()
{
CancellationToken^ token = source->Token;
for (int threads = 1; threads <= 10; threads++)
{
Thread^ newThread = gcnew Thread(gcnew ParameterizedThreadStart(this, &Example::GetRandomNumbers));
newThread->Name = threads.ToString();
newThread->Start(token);
}
this->GetRandomNumbers(token);
countdown->Signal();
// Make sure all threads have finished.
countdown->Wait();
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();
Monitor::Enter(randLock);
result = rand->NextDouble();
Monitor::Exit(randLock);
// 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.
Monitor::Enter(numericLock);
totalCount += perThreadCtr;
totalValue += perThreadTotal;
Monitor::Exit(numericLock);
}
catch (OperationCanceledException^ e) {
Console::WriteLine("Corruption in Thread {1}", e->GetType()->Name,
Thread::CurrentThread->Name);
}
finally {
countdown->Signal();
}
}
};
void main()
{
Example^ ex = gcnew 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
using System;
using System.Threading;
public class Example
{
[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 Example()
{
rand = new Random();
randLock = new Object();
numericLock = new Object();
countdown = new CountdownEvent(1);
source = new CancellationTokenSource();
}
public static void Main()
{
Example ex = new Example();
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 Example
<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
En el ejemplo se garantiza la seguridad de subprocesos de las siguientes maneras:
El ThreadStaticAttribute atributo se usa para definir variables locales de subproceso que realizan un seguimiento del número total de números aleatorios generados y su suma para cada subproceso.
Un bloqueo (la
lock
instrucción en C#, lalock
función en F# y laSyncLock
instrucción de Visual Basic) protege el acceso a las variables para el recuento total y la suma de todos los números aleatorios generados en todos los subprocesos.Se usa un semáforo (el CountdownEvent objeto) para asegurarse de que el subproceso principal se bloquea hasta que todos los demás subprocesos completen la ejecución.
En el ejemplo se comprueba si el generador de números aleatorios se ha dañado al determinar si dos llamadas consecutivas a métodos de generación de números aleatorios devuelven 0. Si se detectan daños, en el ejemplo se usa el CancellationTokenSource objeto para indicar que se deben cancelar todos los subprocesos.
Antes de generar cada número aleatorio, cada subproceso comprueba el estado del CancellationToken objeto. Si se solicita cancelación, el ejemplo llama al CancellationToken.ThrowIfCancellationRequested método para cancelar el subproceso.
El ejemplo siguiente es idéntico al primero, salvo que usa un Task objeto y una expresión lambda en lugar de Thread objetos.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
static Object randLock, numericLock;
static Random rand;
static CancellationTokenSource source;
double totalValue = 0.0;
int totalCount = 0;
public Example()
{
rand = new Random();
randLock = new Object();
numericLock = new Object();
source = new CancellationTokenSource();
}
public static async Task Main()
{
Example ex = new Example();
Thread.CurrentThread.Name = "Main";
await ex.Execute();
}
private 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 Example
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
Difiere del primer ejemplo de las siguientes maneras:
Las variables para realizar un seguimiento del número de números aleatorios generados y su suma en cada tarea son locales para la tarea, por lo que no es necesario usar el ThreadStaticAttribute atributo .
El método estático Task.WaitAll se usa para asegurarse de que el subproceso principal no se completa antes de que finalicen todas las tareas. No es necesario para el CountdownEvent objeto .
La excepción resultante de la cancelación de tareas se muestra en el Task.WaitAll método . En el ejemplo anterior, cada subproceso lo controla.
Generación de diferentes tipos de números aleatorios
El generador de números aleatorios proporciona métodos que permiten generar los siguientes tipos de números aleatorios:
Una serie de Byte valores. Para determinar el número de valores de bytes, se pasa una matriz inicializada al número de elementos que desea que el método devuelva al NextBytes método . En el ejemplo siguiente se generan 20 bytes.
using namespace System; void main() { Random^ rnd = gcnew Random(); array<Byte>^ bytes = gcnew array<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
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 Example 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
Entero único. Puede elegir si desea un entero entre 0 y un valor máximo (Int32.MaxValue - 1) llamando al Next() método , un entero entre 0 y un valor específico llamando al Next(Int32) método o un entero dentro de un intervalo de valores llamando al Next(Int32, Int32) método . En las sobrecargas parametrizadas, el valor máximo especificado es exclusivo; es decir, el número máximo real generado es uno menor que el valor especificado.
En el ejemplo siguiente se llama al Next(Int32, Int32) método para generar 10 números aleatorios entre -10 y 10. Tenga en cuenta que el segundo argumento para el método especifica el límite superior exclusivo del intervalo de valores aleatorios devueltos por el método . En otras palabras, el entero más grande que el método puede devolver es uno menor que este valor.
using namespace System; void main() { Random^ rnd = gcnew 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
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 Example 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
Un valor de punto flotante único de 0,0 a menos de 1,0 llamando al NextDouble método . El límite superior exclusivo del número aleatorio devuelto por el método es 1, por lo que su límite superior real es 0,99999999999999999978. En el ejemplo siguiente se generan 10 números de punto flotante aleatorios.
using namespace System; void main() { Random^ rnd = gcnew 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
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 Example 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
Importante
El Next(Int32, Int32) método permite especificar el intervalo del número aleatorio devuelto. Sin embargo, el maxValue
parámetro , que especifica el número devuelto por el intervalo superior, es un valor exclusivo, no inclusivo. Esto significa que la llamada al Next(0, 100)
método devuelve un valor entre 0 y 99 y no entre 0 y 100.
También puede usar la Random clase para tareas como generar valores T:System.Boolean aleatorios, generar valores de punto flotante aleatorios con un intervalo distinto de 0 a 1, generar enteros aleatorios de 64 bits y recuperar aleatoriamente un elemento único de una matriz o colección. Para estas y otras tareas comunes, consulte la sección How do you use System.Random to... (Cómo se usa System.Random para... ).
Sustituir su propio algoritmo
Puede implementar su propio generador de números aleatorios heredando de la Random clase y proporcionando el algoritmo de generación de números aleatorios. Para proporcionar su propio algoritmo, debe invalidar el Sample método , que implementa el algoritmo de generación de números aleatorios. También debe invalidar los Next()métodos , Next(Int32, Int32)y NextBytes para asegurarse de que llaman al método invalidado Sample . No es necesario invalidar los Next(Int32) métodos y NextDouble .
Para obtener un ejemplo que deriva de la Random clase y modifica su generador de números pseudoaleatorios predeterminado, vea la Sample página de referencia.
¿Cómo se usa System.Random para...
En las secciones siguientes se describe y se proporciona código de ejemplo para algunas de las formas en que es posible que quiera usar números aleatorios en la aplicación.
Recuperar la misma secuencia de valores aleatorios
A veces, quieres generar la misma secuencia de números aleatorios en escenarios de prueba de software y en juego. Las pruebas con la misma secuencia de números aleatorios permiten detectar regresiones y confirmar correcciones de errores. El uso de la misma secuencia de número aleatorio en juegos te permite reproducir juegos anteriores.
Puede generar la misma secuencia de números aleatorios proporcionando el mismo valor de inicialización al Random(Int32) constructor. El valor de inicialización proporciona un valor inicial para el algoritmo de generación de números pseudoalealeadores. En el ejemplo siguiente se usa 100100 como valor de inicialización arbitrario para crear una instancia del Random objeto, se muestran 20 valores de punto flotante aleatorios y se conserva el valor de inicialización. A continuación, restaura el valor de inicialización, crea una instancia de un nuevo generador de números aleatorios y muestra los mismos 20 valores de punto flotante aleatorios. Tenga en cuenta que el ejemplo puede generar secuencias diferentes de números aleatorios si se ejecutan en versiones diferentes de .NET Framework.
using System;
using System.IO;
public class Example
{
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
using namespace System;
using namespace System::IO;
ref class RandomMethods
{
internal:
static void ShowRandomNumbers(int seed)
{
Random^ rnd = gcnew Random(seed);
for (int ctr = 0; ctr <= 20; ctr++)
Console::WriteLine(rnd->NextDouble());
}
static void PersistSeed(int seed)
{
FileStream^ fs = gcnew FileStream(".\\seed.dat", FileMode::Create);
BinaryWriter^ bin = gcnew BinaryWriter(fs);
bin->Write(seed);
bin->Close();
}
static void DisplayNewRandomNumbers()
{
FileStream^ fs = gcnew FileStream(".\\seed.dat", FileMode::Open);
BinaryReader^ bin = gcnew BinaryReader(fs);
int seed = bin->ReadInt32();
bin->Close();
Random^ rnd = gcnew Random(seed);
for (int ctr = 0; ctr <= 20; ctr++)
Console::WriteLine(rnd->NextDouble());
}
};
void main()
{
int seed = 100100;
RandomMethods::ShowRandomNumbers(seed);
Console::WriteLine();
RandomMethods::PersistSeed(seed);
RandomMethods::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 Example
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
Recuperar secuencias únicas de números aleatorios
Proporcionar valores de inicialización diferentes a instancias de la Random clase hace que cada generador de números aleatorios genere una secuencia de valores diferente. Puede proporcionar un valor de inicialización explícitamente llamando al Random(Int32) constructor o implícitamente llamando al Random() constructor . La mayoría de los desarrolladores llaman al constructor sin parámetros, que usa el reloj del sistema. En el ejemplo siguiente se usa este enfoque para crear instancias de dos Random instancias. Cada instancia muestra una serie de 10 enteros aleatorios.
using namespace System;
using namespace System::Threading;
void main()
{
Console::WriteLine("Instantiating two random number generators...");
Random^ rnd1 = gcnew Random();
Thread::Sleep(2000);
Random^ rnd2 = gcnew 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
using System;
using System.Threading;
public class Example
{
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 Example
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
Sin embargo, debido a su resolución finita, el reloj del sistema no detecta diferencias de tiempo inferiores a aproximadamente 15 milisegundos. Por lo tanto, si el código llama a la Random() sobrecarga de .NET Framework para crear instancias de dos Random objetos en sucesión, es posible que proporcione accidentalmente los objetos con valores de inicialización idénticos. (La Random clase de .NET Core no tiene esta limitación). Para ver esto en el ejemplo anterior, convierta en comentario la llamada al Thread.Sleep método y compile y vuelva a ejecutar el ejemplo.
Para evitar que esto suceda, se recomienda crear una instancia de un solo Random objeto en lugar de varios. Sin embargo, dado Random que no es seguro para subprocesos, debe usar algún dispositivo de sincronización si accede a una Random instancia desde varios subprocesos; para obtener más información, vea La seguridad de subprocesos y la clase aleatoria anteriormente en este tema. Como alternativa, puede usar un mecanismo de retraso, como el Sleep método usado en el ejemplo anterior, para asegurarse de que las instancias se producen más de 15 milisegundos.
Recuperar enteros en un intervalo especificado
Puede recuperar enteros en un intervalo especificado llamando al Next(Int32, Int32) método , lo que le permite especificar el límite inferior y superior de los números que desea que devuelva el generador de números aleatorios. El límite superior es un valor exclusivo, no inclusivo. Es decir, no se incluye en el intervalo de valores devueltos por el método . En el ejemplo siguiente se usa este método para generar enteros aleatorios entre -10 y 10. Tenga en cuenta que especifica 11, que es uno mayor que el valor deseado, como el valor del maxValue
argumento en la llamada al método.
using namespace System;
void main()
{
Random^ rnd = gcnew 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
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 Example
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
Recuperar enteros con un número especificado de dígitos
Puede llamar al Next(Int32, Int32) método para recuperar números con un número especificado de dígitos. Por ejemplo, para recuperar números con cuatro dígitos (es decir, números que van de 1000 a 9999), llame al Next(Int32, Int32) método con un minValue
valor de 1000 y un maxValue
valor de 10000, como se muestra en el ejemplo siguiente.
using namespace System;
void main()
{
Random^ rnd = gcnew 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
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 Example
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
Recuperación de valores de punto flotante en un intervalo especificado
El NextDouble método devuelve valores de punto flotante aleatorios que van de 0 a menos de 1. Sin embargo, a menudo querrá generar valores aleatorios en algún otro intervalo.
Si el intervalo entre los valores mínimos y máximos deseados es 1, puede agregar la diferencia entre el intervalo inicial deseado y 0 al número devuelto por el NextDouble método . En el ejemplo siguiente se genera 10 números aleatorios entre -1 y 0.
using namespace System;
void main()
{
Random^ rnd = gcnew 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
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 Example
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
Para generar números de punto flotante aleatorio cuyo límite inferior es 0, pero el límite superior es mayor que 1 (o, en el caso de números negativos, cuyo límite inferior es menor que -1 y límite superior es 0), multiplique el número aleatorio por el límite distinto de cero. En el ejemplo siguiente se genera 20 millones de números de punto flotante aleatorios que van de 0 a Int64.MaxValue. En también se muestra la distribución de los valores aleatorios generados por el método .
using namespace System;
void main()
{
const Int64 ONE_TENTH = 922337203685477581;
Random^ rnd = gcnew Random();
double number;
array<int>^ count = gcnew array<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.
int value = (int) (number / ONE_TENTH);
count[value]++;
}
// 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 %
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 Example
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 %
Para generar números de punto flotante aleatorios entre dos valores arbitrarios, como el Next(Int32, Int32) método hace para enteros, use la fórmula siguiente:
Random.NextDouble() * (maxValue - minValue) + minValue
En el ejemplo siguiente se generan 1 millón de números aleatorios que van de 10,0 a 11,0 y que muestran su distribución.
using namespace System;
void main()
{
Random^ rnd = gcnew Random();
int lowerBound = 10;
int upperBound = 11;
array<int>^ range = gcnew array<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 %)
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 Example
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 * .1
Console.WriteLine("{0:N1} to {1:N1}: {2,8:N0} ({3,7:P2})",
lowerRange, lowerRange + .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 %)
Generación de valores booleanos aleatorios
La Random clase no proporciona métodos que generan Boolean valores. Sin embargo, puede definir su propia clase o método para hacerlo. En el ejemplo siguiente se define una clase, BooleanGenerator
, con un único método, NextBoolean
. La BooleanGenerator
clase almacena un Random objeto como una variable privada. El NextBoolean
método llama al Random.Next(Int32, Int32) método y pasa el resultado al Convert.ToBoolean(Int32) método . Tenga en cuenta que 2 se usa como argumento para especificar el límite superior del número aleatorio. Dado que se trata de un valor exclusivo, la llamada al método devuelve 0 o 1.
using namespace System;
public ref class BooleanGenerator
{
private:
Random^ rnd;
public:
BooleanGenerator()
{
rnd = gcnew Random();
}
bool NextBoolean()
{
return Convert::ToBoolean(rnd->Next(0, 2));
}
};
void main()
{
// Instantiate the Boolean generator.
BooleanGenerator^ boolGen = gcnew 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));
}
// The example displays output like the following:
// Number of true values: 500,004 (50.000 %)
// Number of false values: 499,996 (50.000 %)
using System;
public class Example
{
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 Example
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 %)
En lugar de crear una clase independiente para generar valores aleatorios Boolean , el ejemplo podría simplemente haber definido un único método. Sin embargo, en ese caso, el Random objeto debe haberse definido como una variable de nivel de clase para evitar crear instancias de una nueva Random instancia en cada llamada al método. En Visual Basic, la instancia aleatoria se puede definir como una variable estática en el NextBoolean
método . En el ejemplo siguiente se proporciona una implementación.
using namespace System;
ref class Example
{
private:
static Random^ rnd = gcnew Random();
public:
static void Execute()
{
int totalTrue = 0, totalFalse = 0;
// Generate 1,0000 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));
}
static bool NextBoolean()
{
return Convert::ToBoolean(rnd->Next(0, 2));
}
};
void main()
{
Example::Execute();
}
// The example displays output like the following:
// Number of true values: 499,777 (49.978 %)
// Number of false values: 500,223 (50.022 %)
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 Example
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 %)
Generar enteros aleatorios de 64 bits
Las sobrecargas del Next método devuelven enteros de 32 bits. Sin embargo, en algunos casos, es posible que quiera trabajar con enteros de 64 bits. Puede hacerlo de la siguiente manera:
Llame al NextDouble método para recuperar un valor de punto flotante de precisión doble.
Multiplique ese valor por Int64.MaxValue.
En el ejemplo siguiente se usa esta técnica para generar 20 millones de enteros largos aleatorios y clasificarlos en 10 grupos iguales. A continuación, evalúa la distribución de los números aleatorios contando el número de cada grupo de 0 a Int64.MaxValue. Como se muestra en la salida del ejemplo, los números se distribuyen más o menos por igual a través del intervalo de un entero largo.
using namespace System;
void main()
{
const Int64 ONE_TENTH = 922337203685477581;
Random^ rnd = gcnew Random();
Int64 number;
array<int>^ count = gcnew array<int>(10);
// Generate 20 million long integers.
for (int ctr = 1; ctr <= 20000000; ctr++) {
number = (Int64) (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 %
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 Example
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 %
Una técnica alternativa que usa la manipulación de bits no genera números realmente aleatorios. Esta técnica llama Next() a para generar dos enteros, desplazamientos a la izquierda uno por 32 bits, y las entidades organizativas juntas. Esta técnica tiene dos limitaciones:
Dado que el bit 31 es el bit de signo, el valor del bit 31 del entero largo resultante siempre es 0. Esto se puede solucionar generando un 0 o 1 aleatorio, desplazando a la izquierda 31 bits y ORing con el entero largo aleatorio original.
Más en serio, dado que la probabilidad de que el valor devuelto por Next() sea 0, habrá pocos si hay números aleatorios en el intervalo 0x0-0x00000000FFFFFFFF.
Recuperar bytes en un intervalo especificado
Las sobrecargas del Next método permiten especificar el intervalo de números aleatorios, pero el NextBytes método no. En el ejemplo siguiente se implementa un NextBytes
método que permite especificar el intervalo de los bytes devueltos. Define una Random2
clase que deriva de Random y sobrecarga su NextBytes
método.
using namespace System;
ref class Random2 : Random
{
public:
Random2()
{}
Random2(int seed) : Random(seed)
{}
void NextBytes(array<Byte>^ bytes, Byte minValue, Byte maxValue)
{
for (int ctr = bytes->GetLowerBound(0); ctr <= bytes->GetUpperBound(0); ctr++)
bytes[ctr] = (Byte) Next(minValue, maxValue);
}
};
void main()
{
Random2^ rnd = gcnew Random2();
array<Byte>^ bytes = gcnew array<Byte>(10000);
array<int>^ total = gcnew array<int>(101);
rnd->NextBytes(bytes, 0, 101);
// Calculate how many of each value we have.
for each (Byte 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();
}
}
// 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
using System;
public class Example
{
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 Example
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
El NextBytes(Byte[], Byte, Byte)
método ajusta una llamada al Next(Int32, Int32) método y especifica el valor mínimo y uno mayor que el valor máximo (en este caso, 0 y 101) que queremos devolver en la matriz de bytes. Dado que estamos seguros de que los valores enteros devueltos por el Next método están dentro del intervalo del tipo de Byte datos, podemos convertirlos de forma segura (en C# y F#) o convertirlos (en Visual Basic) de enteros a bytes.
Recuperar un elemento de una matriz o colección de forma aleatoria
Los números aleatorios suelen servir como índices para recuperar valores de matrices o colecciones. Para recuperar un valor de índice aleatorio, puede llamar al Next(Int32, Int32) método y usar el límite inferior de la matriz como el valor de su minValue
argumento y uno mayor que el límite superior de la matriz como el valor de su maxValue
argumento. Para una matriz de base cero, esto equivale a su Length propiedad o a uno mayor que el valor devuelto por el Array.GetUpperBound método . En el ejemplo siguiente se recupera aleatoriamente el nombre de una ciudad en el Estados Unidos de una matriz de ciudades.
using namespace System;
void main()
{
array<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 = gcnew 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
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 Example
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
Recuperar un elemento único de una matriz o colección
Un generador de números aleatorios siempre puede devolver valores duplicados. A medida que el intervalo de números se vuelve más pequeño o el número de valores generados aumenta, crece la probabilidad de duplicados. Si los valores aleatorios deben ser únicos, se generan más números para compensar los duplicados, lo que da lugar a un rendimiento cada vez más deficiente.
Hay varias técnicas para controlar este escenario. Una solución común es crear una matriz o colección que contenga los valores que se van a recuperar y una matriz paralela que contenga números de punto flotante aleatorios. La segunda matriz se rellena con números aleatorios en el momento en que se crea la primera matriz y el Array.Sort(Array, Array) método se usa para ordenar la primera matriz mediante los valores de la matriz paralela.
Por ejemplo, si estás desarrollando un juego solitario, quieres asegurarte de que cada carta se usa solo una vez. En lugar de generar números aleatorios para recuperar una tarjeta y realizar un seguimiento de si esa tarjeta ya se ha tratado, puede crear una matriz paralela de números aleatorios que se pueden usar para ordenar la baraja. Una vez ordenada la baraja, la aplicación puede mantener un puntero para indicar el índice de la siguiente tarjeta en la baraja.
En el ejemplo siguiente se muestra este enfoque. Define una Card
clase que representa una carta de reproducción y una Dealer
clase que trata una baraja de cartas aleatorias. El Dealer
constructor de clase rellena dos matrices: una deck
matriz que tiene ámbito de clase y que representa todas las tarjetas de la baraja; y una matriz local order
que tiene el mismo número de elementos que la deck
matriz y se rellena con valores generados Double aleatoriamente. A Array.Sort(Array, Array) continuación, se llama al método para ordenar la deck
matriz en función de los valores de la order
matriz.
using namespace System;
public enum class Suit { Hearts, Diamonds, Spades, Clubs };
public enum class FaceValue { Ace = 1, Two, Three, Four, Five, Six,
Seven, Eight, Nine, Ten, Jack, Queen,
King };
// A class that represents an individual card in a playing deck.
ref class Card
{
public:
Suit Suit;
FaceValue FaceValue;
String^ ToString() override
{
return String::Format("{0:F} of {1:F}", this->FaceValue, this->Suit);
}
};
ref class Dealer
{
private:
Random^ rnd;
// A deck of cards, without Jokers.
array<Card^>^ deck = gcnew array<Card^>(52);
// Parallel array for sorting cards.
array<Double>^ order = gcnew array<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 = gcnew Random();
// Initialize the deck.
int deckCtr = 0;
for each (auto suit in Enum::GetValues(Suit::typeid)) {
for each (FaceValue faceValue in Enum::GetValues(FaceValue::typeid)) {
Card^ card = gcnew 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);
}
array<Card^>^ Deal(int numberToDeal)
{
if (mustReshuffle) {
Console::WriteLine("There are no cards left in the deck");
return nullptr;
}
array<Card^>^ cardsDealt = gcnew array<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;
}
};
void ShowCards(array<Card^>^ cards)
{
for each (Card^ card in cards)
if (card != nullptr)
Console::WriteLine("{0} of {1}", card->FaceValue, card->Suit);
};
void main()
{
Dealer^ dealer = gcnew Dealer();
ShowCards(dealer->Deal(20));
}
// 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
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 Example
{
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
Notas a los desarrolladores de herederos
En .NET Framework 1.0 y 1.1, una implementación mínima de una clase derivada de Random la invalidación necesaria del Sample() método para definir un algoritmo nuevo o modificado para generar números aleatorios. Después, la clase derivada podría basarse en la implementación de clase base de los Next()métodos , Next(Int32), Next(Int32, Int32), NextBytes(Byte[]), y NextDouble() para llamar a la implementación de clase derivada del Sample() método .
En .NET Framework 2.0 y versiones posteriores, el comportamiento de los Next()métodos , Next(Int32, Int32)y NextBytes(Byte[]) ha cambiado para que estos métodos no llamen necesariamente a la implementación de clase derivada del Sample() método. Como resultado, las clases derivadas de Random ese destino de .NET Framework 2.0 y versiones posteriores también deben invalidar estos tres métodos.
Notas a los autores de las llamadas
No se garantiza que la implementación del generador de números aleatorios de la Random clase siga siendo la misma en las versiones principales de .NET Framework. Como resultado, no debe suponer que la misma inicialización dará como resultado la misma secuencia pseudoalealeatoriedad en distintas versiones de .NET Framework.
Constructores
Random() |
Inicializa una nueva instancia de la clase Random mediante el uso de un valor de inicialización predeterminado. |
Random(Int32) |
Inicializa una nueva instancia de la clase Random utilizando el valor de inicialización especificado. |
Propiedades
Shared |
Proporciona una instancia segura para subprocesos Random que se puede usar simultáneamente desde cualquier subproceso. |
Métodos
Equals(Object) |
Determina si el objeto especificado es igual que el objeto actual. (Heredado de Object) |
GetHashCode() |
Sirve como la función hash predeterminada. (Heredado de Object) |
GetType() |
Obtiene el Type de la instancia actual. (Heredado de Object) |
MemberwiseClone() |
Crea una copia superficial del Object actual. (Heredado de Object) |
Next() |
Devuelve un entero aleatorio no negativo. |
Next(Int32) |
Devuelve un entero aleatorio no negativo que es inferior al máximo especificado. |
Next(Int32, Int32) |
Devuelve un entero aleatorio que está dentro de un intervalo especificado. |
NextBytes(Byte[]) |
Rellena con números aleatorios los elementos de una matriz de bytes especificada. |
NextBytes(Span<Byte>) |
Rellena con números aleatorios los elementos de un intervalo de bytes especificado. |
NextDouble() |
Devuelve un número de punto flotante aleatorio que es mayor o igual que 0,0 y menor que 1,0. |
NextInt64() |
Devuelve un entero aleatorio no negativo. |
NextInt64(Int64) |
Devuelve un entero aleatorio no negativo que es inferior al máximo especificado. |
NextInt64(Int64, Int64) |
Devuelve un entero aleatorio que está dentro de un intervalo especificado. |
NextSingle() |
Devuelve un número de punto flotante aleatorio que es mayor o igual que 0,0 y menor que 1,0. |
Sample() |
Devuelve un número de punto flotante aleatorio entre 0,0 y 1,0. |
ToString() |
Devuelve una cadena que representa el objeto actual. (Heredado de Object) |