What is the easiest way to generate quasi random numbers in C#? - c#

All I want is a pragmatic random number generator in C# so I can say e.g.
int dummyAge = MathHelpers.GetRandomNumber(20,70);
and have it seem quasi random, e.g. to generate dummy data.
Most stack overflow questions on this topic and on the web get into a philosophical discussions on true randomness which is not what I'm interested at the moment, e.g. I did one in PHP a long time ago which uses milliseconds/sleep which is fine for dummy data, I'm just trying to do this in C# quick.
Does anyone have a quick half-decent C# random number generator based on some time seed, etc. or, how could I change the following code so that it always doesn't generate the same 5 number in a row?
using System;
namespace TestRandom23874
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
Console.ReadLine();
}
}
public class MathHelpers
{
public static int GetRandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
}
}

public class MathHelpers
{
private static Random random = new Random();
public static int GetRandomNumber(int min, int max)
{
return random.Next(min, max);
}
}
This way, you're not creating a new Random object every time, rather you're reusing the same one. When you recreate a new one quickly enough, they will yield the same results. If however, you reuse an existing one, you'll get randomness.

BFree's answer is fine, but I think it's also worth mentioning a slightly different pattern - passing the Random instance into anything that needs it, rather than always using a single instance via a static variable. The downside of the latter approach is that Random isn't thread-safe. You either need some locking, or thread-local variables, or avoiding using multiple threads to start with. So I would adjust the original code in the question to:
using System;
namespace TestRandom23874
{
class Program
{
static void Main(string[] args)
{
Random rng = new Random();
Console.WriteLine("the random number is: {0}",
MathHelpers.GetRandomNumber(rng, 1, 10));
Console.WriteLine("the random number is: {0}",
MathHelpers.GetRandomNumber(rng, 1, 10));
Console.WriteLine("the random number is: {0}",
MathHelpers.GetRandomNumber(rng, 1, 10));
Console.WriteLine("the random number is: {0}",
MathHelpers.GetRandomNumber(rng, 1, 10));
Console.WriteLine("the random number is: {0}",
MathHelpers.GetRandomNumber(rng, 1, 10));
}
}
public class MathHelpers
{
public static int GetRandomNumber(Random random, int min, int max)
{
return random.Next(min, max);
}
}
}
It's just basic inversion of control, really. You might have one static RNG with locking round it, used to generate a new instance of Random in a thread-safe way when you need it (by randomly generating a seed and then using that to create the instance) then reusing the Random throughout a particular single-threaded set of operations.

Related

Filling an Array with Random numbers, but the rand-Method doesnt work fast enough? [duplicate]

I have the following function:
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
How I call it:
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
If I step that loop with the debugger during runtime I get different values (which is what I want).
However, if I put a breakpoint two lines below that code, all members of the mac array have equal value.
Why does that happen?
Every time you do new Random() it is initialized using the clock. This means that in a tight loop you get the same value lots of times. You should keep a single Random instance and keep using Next on the same instance.
//Function to get a random number
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static int RandomNumber(int min, int max)
{
lock(syncLock) { // synchronize
return random.Next(min, max);
}
}
Edit (see comments): why do we need a lock here?
Basically, Next is going to change the internal state of the Random instance. If we do that at the same time from multiple threads, you could argue "we've just made the outcome even more random", but what we are actually doing is potentially breaking the internal implementation, and we could also start getting the same numbers from different threads, which might be a problem - and might not. The guarantee of what happens internally is the bigger issue, though; since Random does not make any guarantees of thread-safety. Thus there are two valid approaches:
Synchronize so that we don't access it at the same time from different threads
Use different Random instances per thread
Either can be fine; but mutexing a single instance from multiple callers at the same time is just asking for trouble.
The lock achieves the first (and simpler) of these approaches; however, another approach might be:
private static readonly ThreadLocal<Random> appRandom
= new ThreadLocal<Random>(() => new Random());
this is then per-thread, so you don't need to synchronize.
For ease of re-use throughout your application a static class may help.
public static class StaticRandom
{
private static int seed;
private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
(() => new Random(Interlocked.Increment(ref seed)));
static StaticRandom()
{
seed = Environment.TickCount;
}
public static Random Instance { get { return threadLocal.Value; } }
}
You can use then use static random instance with code such as
StaticRandom.Instance.Next(1, 100);
Mark's solution can be quite expensive since it needs to synchronize everytime.
We can get around the need for synchronization by using the thread-specific storage pattern:
public class RandomNumber : IRandomNumber
{
private static readonly Random Global = new Random();
[ThreadStatic] private static Random _local;
public int Next(int max)
{
var localBuffer = _local;
if (localBuffer == null)
{
int seed;
lock(Global) seed = Global.Next();
localBuffer = new Random(seed);
_local = localBuffer;
}
return localBuffer.Next(max);
}
}
Measure the two implementations and you should see a significant difference.
My answer from here:
Just reiterating the right solution:
namespace mySpace
{
public static class Util
{
private static rnd = new Random();
public static int GetRandom()
{
return rnd.Next();
}
}
}
So you can call:
var i = Util.GetRandom();
all throughout.
If you strictly need a true stateless static method to generate random numbers, you can rely on a Guid.
public static class Util
{
public static int GetRandom()
{
return Guid.NewGuid().GetHashCode();
}
}
It's going to be a wee bit slower, but can be much more random than Random.Next, at least from my experience.
But not:
new Random(Guid.NewGuid().GetHashCode()).Next();
The unnecessary object creation is going to make it slower especially under a loop.
And never:
new Random().Next();
Not only it's slower (inside a loop), its randomness is... well not really good according to me..
I would rather use the following class to generate random numbers:
byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);
1) As Marc Gravell said, try to use ONE random-generator. It's always cool to add this to the constructor: System.Environment.TickCount.
2) One tip. Let's say you want to create 100 objects and suppose each of them should have its-own random-generator (handy if you calculate LOADS of random numbers in a very short period of time). If you would do this in a loop (generation of 100 objects), you could do this like that (to assure fully-randomness):
int inMyRandSeed;
for(int i=0;i<100;i++)
{
inMyRandSeed = System.Environment.TickCount + i;
.
.
.
myNewObject = new MyNewObject(inMyRandSeed);
.
.
.
}
// Usage: Random m_rndGen = new Random(inMyRandSeed);
Cheers.
Every time you execute
Random random = new Random (15);
It does not matter if you execute it millions of times, you will always use the same seed.
If you use
Random random = new Random ();
You get different random number sequence, if a hacker guesses the seed and your algorithm is related to the security of your system - your algorithm is broken. I you execute mult. In this constructor the seed is specified by the system clock and if several instances are created in a very short period of time (milliseconds) it is possible that they may have the same seed.
If you need safe random numbers you must use the class
System.Security.Cryptography.RNGCryptoServiceProvider
public static int Next(int min, int max)
{
if(min >= max)
{
throw new ArgumentException("Min value is greater or equals than Max value.");
}
byte[] intBytes = new byte[4];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetNonZeroBytes(intBytes);
}
return min + Math.Abs(BitConverter.ToInt32(intBytes, 0)) % (max - min + 1);
}
Usage:
int randomNumber = Next(1,100);
Starting from .NET 6, the Random class is now equipped with a static property named Shared:
Provides a thread-safe Random instance that may be used concurrently from any thread.
You could use it like this:
// Function to get random number
public static int RandomNumber(int min, int max)
{
return Random.Shared.Next(min, max);
}
Accessing a thread-safe object has a small overhead, so if you are planning to
generate millions of random numbers on a single thread as fast as possible, it might be preferable to create a dedicated Random instance instead of relying on the Shared.
Why does that happen?
As was answered before, every time you call new Random() you get new copy of Random class initialized with the same clocks (so it returns the same values).
Now, starting from .NET 6, there is easy to use and thread-safe alternative: Random.Shared
In your example you can remove at all function RandomNumber and then use following code (with the same logic, but now it works correct):
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Random.Shared.Next(0, 255));
You can use code like this:
public static class ThreadSafeRandom
{
private static readonly Random _global = new Random();
private static readonly ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>
{
int seed;
lock (_global)
{
seed = _global.Next();
}
return new Random(seed);
});
public static Random Instance => _local.Value;
}
This code can be used as is or via the NuGet package ThreadSafeRandomizer.
EDIT: Since .NET 6.0 you can use Random.Shared.Next() instead. You can still use the above package which chooses between the above code or Random.Shared with preprocessor directives.
I use this:
int randomNumber = int.Parse(Guid.NewGuid().ToString().FirstOrDefault(Char.IsDigit).ToString().Replace("\0", "0"));
Performance: Generating 1 million random number on my PC: 711 ms.
If the Guid not contains any number (i don't know that's possible or not) then 0 will be used as the result.
I solved the problem by using the Rnd() function:
Function RollD6() As UInteger
RollD6 = (Math.Floor(6 * Rnd())) + 1
Return RollD6
End Function
When the form loads, I use the Randomize() method to make sure I don't always get the same sequence of random numbers from run to run.
In Visual Basic this works (probably can be translated to C#, if not a DLL reference can be a solution):
Private Function GetRandomInt(ByVal Min As Integer, ByVal Max As Integer) As Integer
Static Generator As System.Random = New System.Random()
Return Generator.Next(Min, Max)
End Function
There are a lot of solutions, here one: if you want only number erase the letters and the method receives a random and the result length.
public String GenerateRandom(Random oRandom, int iLongitudPin)
{
String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
int iLength = sCharacters.Length;
char cCharacter;
int iLongitudNuevaCadena = iLongitudPin;
String sRandomResult = "";
for (int i = 0; i < iLongitudNuevaCadena; i++)
{
cCharacter = sCharacters[oRandom.Next(iLength)];
sRandomResult += cCharacter.ToString();
}
return (sRandomResult);
}
Always get a positive random number.
var nexnumber = Guid.NewGuid().GetHashCode();
if (nexnumber < 0)
{
nexnumber *= -1;
}

c# Why are the 2 dice always the same number [duplicate]

I have the following function:
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
How I call it:
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
If I step that loop with the debugger during runtime I get different values (which is what I want).
However, if I put a breakpoint two lines below that code, all members of the mac array have equal value.
Why does that happen?
Every time you do new Random() it is initialized using the clock. This means that in a tight loop you get the same value lots of times. You should keep a single Random instance and keep using Next on the same instance.
//Function to get a random number
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static int RandomNumber(int min, int max)
{
lock(syncLock) { // synchronize
return random.Next(min, max);
}
}
Edit (see comments): why do we need a lock here?
Basically, Next is going to change the internal state of the Random instance. If we do that at the same time from multiple threads, you could argue "we've just made the outcome even more random", but what we are actually doing is potentially breaking the internal implementation, and we could also start getting the same numbers from different threads, which might be a problem - and might not. The guarantee of what happens internally is the bigger issue, though; since Random does not make any guarantees of thread-safety. Thus there are two valid approaches:
Synchronize so that we don't access it at the same time from different threads
Use different Random instances per thread
Either can be fine; but mutexing a single instance from multiple callers at the same time is just asking for trouble.
The lock achieves the first (and simpler) of these approaches; however, another approach might be:
private static readonly ThreadLocal<Random> appRandom
= new ThreadLocal<Random>(() => new Random());
this is then per-thread, so you don't need to synchronize.
For ease of re-use throughout your application a static class may help.
public static class StaticRandom
{
private static int seed;
private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
(() => new Random(Interlocked.Increment(ref seed)));
static StaticRandom()
{
seed = Environment.TickCount;
}
public static Random Instance { get { return threadLocal.Value; } }
}
You can use then use static random instance with code such as
StaticRandom.Instance.Next(1, 100);
Mark's solution can be quite expensive since it needs to synchronize everytime.
We can get around the need for synchronization by using the thread-specific storage pattern:
public class RandomNumber : IRandomNumber
{
private static readonly Random Global = new Random();
[ThreadStatic] private static Random _local;
public int Next(int max)
{
var localBuffer = _local;
if (localBuffer == null)
{
int seed;
lock(Global) seed = Global.Next();
localBuffer = new Random(seed);
_local = localBuffer;
}
return localBuffer.Next(max);
}
}
Measure the two implementations and you should see a significant difference.
My answer from here:
Just reiterating the right solution:
namespace mySpace
{
public static class Util
{
private static rnd = new Random();
public static int GetRandom()
{
return rnd.Next();
}
}
}
So you can call:
var i = Util.GetRandom();
all throughout.
If you strictly need a true stateless static method to generate random numbers, you can rely on a Guid.
public static class Util
{
public static int GetRandom()
{
return Guid.NewGuid().GetHashCode();
}
}
It's going to be a wee bit slower, but can be much more random than Random.Next, at least from my experience.
But not:
new Random(Guid.NewGuid().GetHashCode()).Next();
The unnecessary object creation is going to make it slower especially under a loop.
And never:
new Random().Next();
Not only it's slower (inside a loop), its randomness is... well not really good according to me..
I would rather use the following class to generate random numbers:
byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);
1) As Marc Gravell said, try to use ONE random-generator. It's always cool to add this to the constructor: System.Environment.TickCount.
2) One tip. Let's say you want to create 100 objects and suppose each of them should have its-own random-generator (handy if you calculate LOADS of random numbers in a very short period of time). If you would do this in a loop (generation of 100 objects), you could do this like that (to assure fully-randomness):
int inMyRandSeed;
for(int i=0;i<100;i++)
{
inMyRandSeed = System.Environment.TickCount + i;
.
.
.
myNewObject = new MyNewObject(inMyRandSeed);
.
.
.
}
// Usage: Random m_rndGen = new Random(inMyRandSeed);
Cheers.
Every time you execute
Random random = new Random (15);
It does not matter if you execute it millions of times, you will always use the same seed.
If you use
Random random = new Random ();
You get different random number sequence, if a hacker guesses the seed and your algorithm is related to the security of your system - your algorithm is broken. I you execute mult. In this constructor the seed is specified by the system clock and if several instances are created in a very short period of time (milliseconds) it is possible that they may have the same seed.
If you need safe random numbers you must use the class
System.Security.Cryptography.RNGCryptoServiceProvider
public static int Next(int min, int max)
{
if(min >= max)
{
throw new ArgumentException("Min value is greater or equals than Max value.");
}
byte[] intBytes = new byte[4];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetNonZeroBytes(intBytes);
}
return min + Math.Abs(BitConverter.ToInt32(intBytes, 0)) % (max - min + 1);
}
Usage:
int randomNumber = Next(1,100);
Starting from .NET 6, the Random class is now equipped with a static property named Shared:
Provides a thread-safe Random instance that may be used concurrently from any thread.
You could use it like this:
// Function to get random number
public static int RandomNumber(int min, int max)
{
return Random.Shared.Next(min, max);
}
Accessing a thread-safe object has a small overhead, so if you are planning to
generate millions of random numbers on a single thread as fast as possible, it might be preferable to create a dedicated Random instance instead of relying on the Shared.
Why does that happen?
As was answered before, every time you call new Random() you get new copy of Random class initialized with the same clocks (so it returns the same values).
Now, starting from .NET 6, there is easy to use and thread-safe alternative: Random.Shared
In your example you can remove at all function RandomNumber and then use following code (with the same logic, but now it works correct):
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Random.Shared.Next(0, 255));
You can use code like this:
public static class ThreadSafeRandom
{
private static readonly Random _global = new Random();
private static readonly ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>
{
int seed;
lock (_global)
{
seed = _global.Next();
}
return new Random(seed);
});
public static Random Instance => _local.Value;
}
This code can be used as is or via the NuGet package ThreadSafeRandomizer.
EDIT: Since .NET 6.0 you can use Random.Shared.Next() instead. You can still use the above package which chooses between the above code or Random.Shared with preprocessor directives.
I use this:
int randomNumber = int.Parse(Guid.NewGuid().ToString().FirstOrDefault(Char.IsDigit).ToString().Replace("\0", "0"));
Performance: Generating 1 million random number on my PC: 711 ms.
If the Guid not contains any number (i don't know that's possible or not) then 0 will be used as the result.
I solved the problem by using the Rnd() function:
Function RollD6() As UInteger
RollD6 = (Math.Floor(6 * Rnd())) + 1
Return RollD6
End Function
When the form loads, I use the Randomize() method to make sure I don't always get the same sequence of random numbers from run to run.
In Visual Basic this works (probably can be translated to C#, if not a DLL reference can be a solution):
Private Function GetRandomInt(ByVal Min As Integer, ByVal Max As Integer) As Integer
Static Generator As System.Random = New System.Random()
Return Generator.Next(Min, Max)
End Function
There are a lot of solutions, here one: if you want only number erase the letters and the method receives a random and the result length.
public String GenerateRandom(Random oRandom, int iLongitudPin)
{
String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
int iLength = sCharacters.Length;
char cCharacter;
int iLongitudNuevaCadena = iLongitudPin;
String sRandomResult = "";
for (int i = 0; i < iLongitudNuevaCadena; i++)
{
cCharacter = sCharacters[oRandom.Next(iLength)];
sRandomResult += cCharacter.ToString();
}
return (sRandomResult);
}
Always get a positive random number.
var nexnumber = Guid.NewGuid().GetHashCode();
if (nexnumber < 0)
{
nexnumber *= -1;
}

Two different random number generators giving the same answer?

static void Main(string[] args)
{
//random number gen
Console.WriteLine("Array Random Number:");
randomGenA();
Console.WriteLine("------------------");
//LIST: random movie picker...
Console.WriteLine("List Random Number:");
randomGenB();
Console.WriteLine("------------------");
Console.ReadLine();
}
static void randomGenA()
{
Random randomA = new Random();
int randomNumA = randomA.Next(51);
Console.WriteLine(randomNumA);
}
static void randomGenB()
{
Random randomB = new Random();
int randomNumB = randomB.Next(0,51);
Console.WriteLine(randomNum);
}
}
I wanted them both to produce two different random numbers but instead I keep getting the same random number from both of them. Why does it do this?
Declare a class level random and use it in your methods:
private static Random _random = new Random();
Your methods would look like:
static void randomGenA()
{
int randomNumA = _random.Next(51);
Console.WriteLine(randomNumA);
}
static void randomGenB()
{
int randomNumB = _random.Next(0,51);
Console.WriteLine(randomNum);
}
Check this out for further reading: http://www.dotnetperls.com/random
As per the documentation:
https://msdn.microsoft.com/en-us/library/system.random%28v=vs.110%29.aspx
Two Randoms with the same seed will provide the same sequence of numbers. Simply don't use the same seed. If you don't specify a seed, it uses the system time. Wait some time between the two instantiations and it will use two different system times.

C# Random Image from Directory [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
Consider this method:
private static int GenerateRandomNumber(int seed, int max)
{
return new Random(seed).Next(max);
}
On my machine, executing this loop yields the same number through 1500 iterations:
for (int i = 0; i < 1501; i++)
{
int random = GenerateRandomNumber(100000000, 999999999);
Console.WriteLine(random.ToString());
Console.ReadKey();
}
I get 145156561, for every single iteration.
I don't have a pressing issue, I was just curious about this behavior because .Next(max) says "Returns a Non Negative random number less than the specified maximum. Perhaps I am not understanding something basic.
You're always seeding a new instance with the same seed, and then grabbing the first max. By using a Seed, you're guaranteeing the same results.
If you want to have a static, random number generation that does different results, you should rework this a bit. However, since Random is not threadsafe, it requires some synchronization when used statically. Something like:
private static Random random;
private static object syncObj = new object();
private static void InitRandomNumber(int seed)
{
random = new Random(seed);
}
private static int GenerateRandomNumber(int max)
{
lock(syncObj)
{
if (random == null)
random = new Random(); // Or exception...
return random.Next(max);
}
}
Dilbert has encountered the same problem back in 2001:
http://dilbert.com/strips/comic/2001-10-25/
Coincidence?
I don't think so.
And random.org agrees : http://www.random.org/analysis/
The problem is that you are creating a new Random instance with the same seed number each time. You should create a single Random instance (store it in a static if necessary) and simply call the next method on that same instance.
Random number generation is not truly random, see this Wikipedia entry for more details.
Salam to All,
Well it drove me crazy as well. The answer is simple. Change the seed before you generate random.
Example:
I want to generate random number between 1 to 10
Random rnd = new Random(DateTime.Now.Second);
int random_number = rnd.Next(10);
Put it inside a loop and run it three times. It will give out random numbers below 10.
Pseudo-random number generator usually work by choosing a seed, and then generating a deterministic sequence based on that seed. Choosing the same seed every time, you generate the same sequence.
There are "only" 2^32 different random sequences in .NET.
Not sure how the internals work.. check wiki for it, but it's very simple.
public class MathCalculations
{
private Random rnd = new Random();
public Int32 getRandom(Int32 iMin, Int32 iMax)
{
return rnd.Next(iMin, iMax);
}
}
public class Main
{
MathCalculations mathCalculations = new MathCalculations();
for (int i = 0; i < 6; i++)
{
getRandom(0,1000);
}
}
will generate Number1, Number2, Number3, Number4, Number5, Number6 (1 seed, 1 sequence of many numbers, random*not really, but approx.*)
if you however do this:
public class MathCalculations
{
public Int32 getRandom(Int32 iMin, Int32 iMax)
{
Random rnd = new Random();
return rnd.Next(iMin, iMax);
}
}
public class Main
{
MathCalculations mathCalculations = new MathCalculations();
for (int i = 0; i < 6; i++)
{
getRandom(0,1000);
}
}
You will now get Number1, Number1, Number1, Number1, Number1, Number1 (1 seed, 6 equal sequences of many numbers, always pick the same starting number from each equal sequence).. At some point Number1 will be different, because the seed changes over time.. but you need to wait some time for this, nonetheless, you never pick number2 from the sequence.
The reason is, each time you generate a new sequence with the same seed, hence the sequence is the same over and over again, and each time your random generated will pick the first number in it's sequence, which, with the same seed, is of course always the same.
Not sure if this is technically correct by the underlying methods of the random generator, but that's how it behaves.
In the event that anyone is looking for a "quick and dirty" "solution" (and I use that term with caution) then this will suffice for most.
int secondsSinceMidnight = Convert.ToInt32(DateTime.Now.Subtract(DateTime.Today).TotalSeconds);
Random rand = new Random(secondsSinceMidnight);
var usuallyRandomId = rand.Next();
Please note my use of usually random. I agree that the item marked as the answer is a more correct way of doing this.

Why am I getting strange results when generating Random() numbers?

My program needs to:
a. Generate an array of 20 random integers from zero to nine. Search for the first occurrence, if any, of the number 7, and report its position in the array.
b. Repeat the computation of part a 1000 times, and for each position in the array, report the number of times that the first occurrence of a 7 in the array is at that position
However whenever I run the program I get strange results (different every time) such as:
No sevens found at any position
1000 sevens found at one position and no sevens found anywhere else
Hundreds of sevens found in 2 positions, and none found anywhere else.
Does anyone have an idea what is wrong with my program?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Week_6_Project_2
{
class Program
{
static int intArrayLength = 20;
static int[] resultsArray = new int[intArrayLength];
public static Array generateRandomArray() {
int[] randomNumberArray = new int[intArrayLength];
Random random = new Random();
int popcounter = 0;
while (popcounter < intArrayLength) {
randomNumberArray[popcounter] = random.Next(0, 10);
popcounter += 1;
}
return randomNumberArray;
}
public static void searchForSevens()
{
int counter = 0;
int[] randomArray = (int[])generateRandomArray();
while (counter < intArrayLength)
{
if (randomArray[counter] == 7)
{
resultsArray[counter] += 1;
counter = intArrayLength;
}
counter += 1;
}
}
static void Main()
{
int searchCounter = 0;
while (searchCounter < 1000)
{
searchForSevens();
searchCounter += 1;
}
int displayCounter = 0;
while (displayCounter < intArrayLength)
{
Console.WriteLine("Number of first occurrence of 7 at position {0} = {1}", displayCounter, resultsArray[displayCounter]);
displayCounter += 1;
}
Console.ReadLine();
}
}
}
Your main problem is that each searchForSevens() test only takes a small fraction of time and the Random class uses auto-seeding from the clock. The clock however has a limited resolution. The result is that many (sometimes all) of your random sequences will be the same. And at most you will have 2 or 3 different result sets.
The simple fix for this single-threaded program is to use 1 static instance of Random.
You're instantiating a new instance of Random every time you call the generateRandomArray method. Since the random number generator uses the current time as a seed, instantiating two Random instances at the same time results in the same numbers being generated, which explains your unexpected results.
To solve your problem, you should only instantiate one Random instance, store it in private field, and reuse it every time you call the Next method.
The problem I assume stems from the fact, that Random() uses current time as seed. And the computation happens so fast, that each time new Random() is called, it uses same time. So you get same sequence of numbers.
To fix this, you simply need to set seed by yourself, incremmenting it every cycle should be enough.
long base = DateTime.Now.TotalMilliseconds;
Random rand = new Random(base+searchCounter);
.. something like that.
I will not answer but will try to give an analogy for the people that think that they need more then one Random instance...
Suppose that you need to fill 6 sheets of paper with random numbers from 1-6. Ask yourself this: do you need 6 dices or one to do the job? If you answer that you need more than one dice, ask yourself this: how different or more random is throwing different dice instead of same dice every time?
I mean, if you throw ONE on a dice, next throw of a dice won't have any less chance to be ONE again than it would be any other number. It goes against intuition, but it is mathematically and statistically so.
In your original code, you're calling the Random method in rapid succession [broken example based on OP's original code], thus seeding the method with the same number, resulting in duplicate "random" numbers. Creating a static member will ensure randomness simply because you're only creating a single instance of it.
Try creating a single static instance of random like this. [static member example].
static readonly Random Random = new Random();
Based on this, here's how I would solve your particular problem.
using System;
namespace Week_6_Project_2
{
class Program
{
// ******************************************
// THIS IS A SINGLE INSTANCE OF Random.
// read below as to why I'm seeding the instantiation of Random();
static readonly Random Random = new Random(Guid.NewGuid().GetHashCode());
// ******************************************
private const int IntArrayLength = 20;
static readonly int[] ResultsArray = new int[IntArrayLength];
public static Array GenerateRandomArray()
{
var randomNumberArray = new int[IntArrayLength];
var popcounter = 0;
while (popcounter < IntArrayLength)
{
randomNumberArray[popcounter] = Random.Next(0, 10);
popcounter += 1;
}
return randomNumberArray;
}
public static void SearchForSevens()
{
var counter = 0;
var randomArray = (int[])GenerateRandomArray();
while (counter < IntArrayLength)
{
if (randomArray[counter] == 7)
{
ResultsArray[counter] += 1;
counter = IntArrayLength;
}
counter += 1;
}
}
static void Main()
{
var searchCounter = 0;
while (searchCounter < 1000)
{
SearchForSevens();
searchCounter += 1;
}
var displayCounter = 0;
while (displayCounter < IntArrayLength)
{
Console.WriteLine("Number of first occurrence of 7 at position {0} = {1}", displayCounter, ResultsArray[displayCounter]);
displayCounter += 1;
}
Console.ReadLine();
}
}
}
Further reading about Random()
Beyond the answer above, sometimes it is necessary to seed Random(int); (I like to use the HashCode of a Guid) to ensure further randomness. This is because the default seed uses the clock which from the docs [microsoft] has a finite resolution. If your class is instantiated multiple times in quick succession (< 16ms), you will get the same seed from the clock... this breaks stuff.
[example of seeded Random(int) run in rapid succession with random results]
"using the parameterless constructor to create different Random objects in close succession creates random number generators that produce identical sequences of random numbers."
hear me when I say that you should NOT instantiate a new Random on every iteration of a loop -- use a static member
Another valid reason to implement your own seed is when you want to recreate a random sequence [example of two identical lists based on same seed]. Re-using the same seed will recreate the sequence since the sequence is based on the seed.
note: others might say that seeding it is not necessary [link], but I personally believe that for the additional few keystrokes and the microscopic hit on the clock, you might as well increase the probability of a unique seed. It doesn't hurt anything, and in some situations it can help.

Categories