Random Class
Updated: March 2011
Represents a pseudo-random number generator, a device that produces a sequence of numbers that meet certain statistical requirements for randomness.
Assembly: mscorlib (in mscorlib.dll)
The Random type exposes the following members.
| Name | Description | |
|---|---|---|
|
Random | Initializes a new instance of the Random class, using a time-dependent default seed value. |
|
Random(Int32) | Initializes a new instance of the Random class, using the specified seed value. |
| Name | Description | |
|---|---|---|
|
Equals(Object) | Determines whether the specified Object is equal to the current Object. (Inherited from Object.) |
|
Finalize | Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object.) |
|
GetHashCode | Serves as a hash function for a particular type. (Inherited from Object.) |
|
GetType | Gets the Type of the current instance. (Inherited from Object.) |
|
MemberwiseClone | Creates a shallow copy of the current Object. (Inherited from Object.) |
|
Next | Returns a nonnegative random number. |
|
Next(Int32) | Returns a nonnegative random number less than the specified maximum. |
|
Next(Int32, Int32) | Returns a random number within a specified range. |
|
NextBytes | Fills the elements of a specified array of bytes with random numbers. |
|
NextDouble | Returns a random number between 0.0 and 1.0. |
|
Sample | Returns a random number between 0.0 and 1.0. |
|
ToString | Returns a string that represents the current object. (Inherited from Object.) |
Pseudo-random numbers are chosen with equal probability from a finite set of numbers. The chosen numbers are not completely random because a definite mathematical algorithm is used to select them, but they are sufficiently random for practical purposes. The current implementation of the Random class is based on a modified version of Donald E. Knuth's subtractive random number generator algorithm. For more information, see D. E. Knuth. "The Art of Computer Programming, volume 2: Seminumerical Algorithms". Addison-Wesley, Reading, MA, second edition, 1981.
The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random. By default, the parameterless constructor of the Random class uses the system clock to generate its seed value, while its parameterized constructor can take an Int32 value based on the number of ticks in the current time. However, because the clock has finite resolution, using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers. The following example illustrates that two Random objects that are instantiated in close succession generate an identical series of random numbers.
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 the following output to the console: // 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
This problem can be avoided by creating a single Random object rather than multiple ones.
To improve performance, create one Random object to generate many random numbers over time, instead of repeatedly creating a new Random objects to generate one random number.
To generate a cryptographically secure random number suitable for creating a random password, for example, use a class derived from System.Security.Cryptography.RandomNumberGenerator such as System.Security.Cryptography.RNGCryptoServiceProvider.
Notes to Callers
The implementation of the random number generator in the Random class is not guaranteed to remain the same across major versions of the .NET Framework. As a result, your application code should not assume that the same seed will result in the same pseudo-random sequence in different versions of the .NET Framework.
Notes to Inheritors
In the .NET Framework versions 1.0 and 1.1, a minimum implementation of a class derived from Random required overriding the Sample method to define a new or modified algorithm for generating random numbers. The derived class could then rely on the base class implementation of the Random.Next, Random.Next(Int32), Random.Next(Int32, Int32), NextBytes, and NextDouble methods to call the derived class implementation of the Sample method.
In the .NET Framework version 2.0 and later, the behavior of the Random.Next, Random.Next(Int32, Int32), and NextBytes methods have changed so that these methods do not necessarily call the derived class implementation of the Sample method. As a result, classes derived from Random that target the .NET Framework 2.0 and later should also override these three methods.
The following example creates a single random number generator and calls its NextBytes, Next, and NextDouble methods to generate sequences of random numbers within different ranges.
// Instantiate random number generator using system-supplied value as seed. Random rand = new Random(); // Generate and display 5 random byte (integer) values. byte[] bytes = new byte[4]; 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); // Sample console output might appear as follows: // 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
Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows XP SP2 x64 Edition, Windows Server 2008 (Server Core not supported), Windows Server 2008 R2 (Server Core supported with SP1 or later), Windows Server 2003 SP2
The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
- 8/12/2011
- Artem Odin
This means that one has to be careful when using the Random Class.
Here are two blog posts with more details, comments and code samples on this topic:
- Another issue with the .NET Random class (http://diniscruz.blogspot.com/2011/07/another-issue-with-net-random-class.html)
- Humm … .NET Random class is not Thread Safe? (http://o2platform.wordpress.com/2011/07/16/humm-net-random-class-is-not-thread-safe/)
The Random Class and Thread Safety
This lack of thread safety is documented in the Thread Safety section of this topic. For more information about how to call Random instance methods safely from multiple threads, see the "Random Instance Methods and Thread Safety" section of the following post.
--Ron Petrusha
Common Language Runtime User Education
Microsoft Corporation
- 7/16/2011
- Dinis Cruz
- 8/5/2011
- R Petrusha - MSFT
Although the documentation says "Any instance members are not guaranteed to be thread safe.", the failure case of using a single Random instance from multiple threads is severe enough that I think it deserves special mention.
If the Random class is accessed from multiple threads at the same time, the random number generator will break, and Random.Next() will return all zeros, forever. If you're doing anything with multiple threads, be very sure that you're not accessing a single Random object simultaneously from multiple threads
Random Instance Methods and Thread Safety
This limitation, as you point out, is already documented in the Thread Safety section of this topic. If the members of a type are not guaranteed to be thread-safe, simultaneous or near-simultaneous calls to the members of an instance of the type created on one thread from other threads are likely to produce unexpected or erroneous results. And as you also point out, developers should ""be very sure that you're not accessing a single Random object simultaneously from multiple threads". It's important to emphasize, though, that this does not mean that calls to instance methods that are not thread-safe should not be made from multiple threads. Instead, you can safely call instance methods from multiple threads as long as you ensure that only a single thread can make the call at any particular time. There are a variety of ways to do this by using the synchronization types in the System.Threading namespace, or by using language constructs such as lock in C# and SyncLock in Visual Basic.
For example, the following example illustrates the problem. A main thread and ten additional threads each try to retrieve two million random numbers. A relatively small number of the potential twelve million calls are executed before the random number generator fails.
using System;
using System.Threading;
public class Example
{
[ThreadStatic] static double previous = 0.0;
[ThreadStatic] static bool abnormal;
[ThreadStatic] static int perThreadCtr = 0;
Random rand;
public Example()
{
rand = new Random();
}
public static void Main()
{
Example ex = new Example();
Thread.CurrentThread.Name = "Main";
ex.Execute();
Console.WriteLine("Program execution concluded...");
}
private void Execute()
{
for (int threads = 1; threads <= 10; threads++)
{
Thread newThread = new Thread(new ThreadStart(this.GetRandomNumbers));
newThread.Name = threads.ToString();
newThread.Start();
}
this.GetRandomNumbers();
}
private void GetRandomNumbers()
{
double result = 0.0;
for (int ctr = 0; ctr < 2000000; ctr++)
{
result = rand.NextDouble();
if (result == previous) {
abnormal = true;
break;
}
else {
previous = result;
}
perThreadCtr++;
}
// get last result
if (abnormal)
Console.WriteLine("Result is {0} in Thread {1}", previous, Thread.CurrentThread.Name);
Console.WriteLine("Thread {0} finished execution of {1:N0} iterations.",
Thread.CurrentThread.Name, perThreadCtr);
}
}
By using the C# lock statement, as in the following example, we can ensure the thread safety of our application, and also ensure that each thread retrieves two million random numbers.
using System;
using System.Threading;
public class Example
{
[ThreadStatic] static double previous = 0.0;
[ThreadStatic] static bool abnormal;
[ThreadStatic] static int perThreadCtr = 0;
[ThreadStatic] static int ctr = 0;
private static Object lockObj;
Random rand;
public Example()
{
rand = new Random();
lockObj = new Object();
}
public static void Main()
{
Example ex = new Example();
Thread.CurrentThread.Name = "Main";
ex.Execute();
Console.WriteLine("Program execution concluded...");
}
private void Execute()
{
for (int threads = 1; threads <= 10; threads++)
{
Thread newThread = new Thread(new ThreadStart(this.GetRandomNumbers));
newThread.Name = threads.ToString();
newThread.Start();
}
this.GetRandomNumbers();
}
private void GetRandomNumbers()
{
double result = 0.0;
for (ctr = 0; ctr < 2000000; ctr++)
{
lock (lockObj) {
result = rand.NextDouble();
}
if (result == previous) {
abnormal = true;
break;
}
else {
previous = result;
}
perThreadCtr++;
}
// get last result
if (abnormal)
Console.WriteLine("Result is {0} in Thread {1}", previous, Thread.CurrentThread.Name);
Console.WriteLine("Thread {0} finished execution of {1:N0} iterations.",
Thread.CurrentThread.Name, perThreadCtr);
}
}
--Ron Petrusha
Common Language Runtime User Education
Microsoft Corporation
- 5/20/2011
- David J. Yaw
- 8/5/2011
- R Petrusha - MSFT
StringBuilder strRandom = new StringBuilder("");
for (int i = 0; i <10; i++)
{
Random Rnd = new Random();
int Rand = Rnd.Next(20);
strRandom = strRandom.Append(Rand.ToString() + "," + System.Environment.NewLine);
Rnd = null;
}
Lbl.Text = strRandom.ToString();
Random Produces Pseudo-Random Numbers
The exact sequence of random numbers generated by the Random class depends on the seed value with which the random number generator is instantiated. Given identical seed values, instances of the Random class will generate identical sequences of random numbers.
In the case of this example, the parameterless constructor instantiates a Random instance with a seed value based on the system clock. Given the speed with which the for loop in this example executes, the practical effect is that each instance of Random is passed the same seed value. As a result, the same sequence of random numbers is generated. This is mentioned in the documentation at http://msdn.microsoft.com/en-us/library/system.random.aspx: "However, because the clock has finite resolution, using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers." The documentation for the default constructor at http://msdn.microsoft.com/en-us/library/h343ddh9.aspx contains more detail: "The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to the Random(Int32) constructor."
In the case of this example, instantiating a single Random object outside of the for loop solves the problem:
StringBuilder strRandom = new StringBuilder("");
Random Rnd = new Random();
for (int i = 0; i <10; i++)
{
int Rand = Rnd.Next(20);
strRandom = strRandom.Append(Rand.ToString() + "," + System.Environment.NewLine);
}
Console.WriteLine(strRandom.ToString());
I hope that this helps.
--Ron Petrusha
Common Language Runtime Developer Content
Microsoft Corporation
- 3/22/2011
- Uddipto Banerji
- 3/23/2011
- R Petrusha - MSFT
open System
// The MAIN in F#
[<STAThread>]
[<EntryPoint>]
let main (args) =
let urandom = new Random()
match args with
| _ ->
// this will sleep for a random time multiplied by 10...
System.Threading.Thread.Sleep(10 * urandom.Next());
0
- 2/24/2011
- LMA1980
I'm studing the Random numbers generation and I never get the max value of my random.Next when setting the minValue and maxValue.
Here's the code I'm using:
Dim rnd As New Random
For i = 0 To 1500000
Dim num = rnd.Next(1, 9)
If num = 9 Then
MsgBox("i=" & i & " - num=" & num)
End If
Next
This code loops 1,500,000 times generating a random number between 1 and 9 and never gets 9 as the generated number.
If I set rnd.Next(1,10) I can get 9 before the 10th loop...
Is there any rule I missed about the ".Next" method used with minValue and maxValue does return the "maxValue" at all? (or should I just use "maxValue +1" to get the maximum value returned from this function?)
Regards,
Victor
Why Random.Next Never Returns the Maximum Value
The behavior that you're describing is documented and is by design. According to the documentation, the maxValue parameter in the Random.Next(Int32, Int32) method represents "the exclusive upper bound of the random number returned." "Exclusive" means that that value is not part of the set. In other words, the second integer parameter represents the first integer that is outside the range of the values returned by the method.
Actually, there are three overloads of Random.Next, and each behaves in this way. The parameterless overload returns an integer that is greater than or equal to zero and less than Int32.MaxValue. Random.Next(Int32) returns an integer that ranges from zero to one less than its parameter. And Random.Next(Int32, Int32) returns an integer that ranges from the value of its first parameter to one less than the value of its second parameter.
--Ron Petrusha
Common Language Runtime Developer Content
Microsoft Corporation
- 2/21/2011
- vreboucas
- 2/22/2011
- R Petrusha - MSFT
public static class RandomGenerator
{
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static bool GetBoolean()
{
lock (syncLock)
{
return (random.Next(2) == 1);
}
}
public static int GetInteger(int MaxValue)
{
lock (syncLock)
{
return random.Next(0, MaxValue);
}
}
public static byte GetByte()
{
return ((byte)GetInteger(256));
}
public static string GetUppercaseAlphabetString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(65 + GetInteger(27));
builder.Append(ch);
}
return builder.ToString();
}
public static DateTime GetDateBetween1995andNow()
{
DateTime start = new DateTime(1995, 1, 1);
int range = ((TimeSpan)(DateTime.Today - start)).Days;
return start.AddDays(GetInteger(range));
}
public static double GetDouble()
{
lock (syncLock)
{
return random.NextDouble();
}
}
}
- 12/25/2010
- Lasne Khalid
- 2/6/2011
- W1N9Zr0
- 10/12/2010
- tosa
