Random not that random [duplicate] - c#

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 8 years ago.
I am using Random to generate a sequence of random number. I am constructing the random object just once and then inside the loop generating the random values (300 of them). The problem is that once I get all the values and do a sort on them I realize that some of them are equal and/or sequential: I am generating numbers from 0 to 50000.
This is my script:
Random rnd = new Random();
for (int n=0; n < 300; n++)
{
int RndNumber = rnd.Next(0, 50000);
System.Threading.Thread.Sleep(3);
}
Can someone have a clue on why this is happening, and how can I improve this to make it more random?

So this is the birthday paradox*. When you draw 300 numbers from 50000 the approximate probability that at least two of them are equal is
p(300) = 1 - exp(-300 * 300 / (2 * 50000))
= 0.59
(I could work out the exact probability but I'm lazy!.)
So, chances are more likely than not that you'll have a collision. Sequential is even more likely (now you don't need a collision, you just need n - 1 and n or n and n + 1 to be hit for some n).
Random is fickle.
*: In case you're not familiar with it, it says that if you have twenty-three people in a room, it is more likely than not that at least two people in the room share the same birthday.
!: Okay, I worked it out. It's 0.5953830515549951746819986449....

Research:
If you use the constructor without parameters new Random() the seed is depending on the current servertime.
Random(): "Initializes a new instance of the Random class, using a time-dependent"
http://msdn.microsoft.com/en-us/library/system.random.aspx
So, if I try it like this:
for(int i = 0; i < 1000; i++)
{
Random ran = new Random();
Console.WriteLine(ran.Next(50001));
}
I only get 3 different numbers about 300 times within a thousand calls! Not that random...
Setting the seed in the constructor new Random(0) returns a fix serie of numbers.
e.g. new Random(0).Next(50) always! returns 36. Try it yourself, if you don't trust me;
What we need for "real" random numbers is a changing seed, that's independent of time.
I'm using Hashcode of changing values:
e.g. Guid.NewGuid().GetHashCode() or DateTime.Now.GetHashCode()
Result:
Random ran = new Random(Guid.NewGuid().GetHashCode());
for(int i = 0; i < 1000; i++)
{
Console.WriteLine(ran.Next(50001));
}
or (for better performance):
for(int i = 0; i < 1000; i++)
{
int val = Guid.NewGuid().GetHashCode() % 50001;
val = val > 0 ? val : -val;
Console.WriteLine(val);
}
PS: The maximum of the Next(max)-method is always max - 1;
-> ran.Next(11) can return 0,1,2,...,8,9,10. Not 11!

As an explanation of why you're seeing the occasional duplicate, Jason's answer is right on.
If what you want is 300 distinct random numbers, what about something like this?
static IEnumerable<int> GetRandoms(int min, int max)
{
var rand = new Random();
while (true)
{
yield return rand.Next(min, max);
}
}
var distinctRandoms = GetRandoms(0, 50000).Distinct().Take(300);

Related

I need some help to complete this code of non-duplicate random numbers

I need some help to do my homework. I should write non-duplicate random numbers. I'm able to show random numbers but I don't know about non-duplicate.
Here's my code:
Random r = new Random();
for (int i = 0; i < 40; i++)
{
int temp = r.Next(0, 100);
Console.WriteLine(temp);
}
What do I need to do to generate non-duplicate number?
Note that this answer only deals with (relatively) small, pre-determined sets.
The reason the other (simple) solution is inefficient is this: you want to generate 100 random numbers between 0 and 99. You get to the point where you have generated 90 random numbers, and just need 10 more.
The problem is that you're still generating numbers between 0 and 99 every time, except now your chance of finding a number that hasn't already been generated is 1 in 10. So 9 of every 10 numbers you generate has already been added to the list.
Once you get down to just needing 1 number, your chance of generating the remaining 1 that hasn't already been generated is 1 in 100. So for every 100 numbers you generate, only 1 of them will be the last possible number.
I'm sure this is simplifying things given that the Random class is pseudo-random (i.e. it's an algorithm that appears random), but this does explain your situation and why the other answer will be slower.
An improved solution would be this:
// Add all of the numbers 0 to 100 to a list
var availableNumbers = new List<int>();
for (int i = 0; i < 100; ++i)
{
availableNumbers.Add(i);
}
Random random = new Random();
for (int i = 0; i < 40; ++i)
{
// Choose a random position in the available numbers list
var idx = random.Next(0, availableNumbers.Count);
// Print the number from this position in the list
Console.WriteLine(availableNumbers[idx]);
// Remove the item at this position
availableNumbers.RemoveAt(idx);
}
Because we start with a list of all available numbers, we are able to choose numbers from it at random. Removing items from the available numbers list means that they are not available to be chosen a second time. We no longer have to try many times to find an unused number, as removing them when we select them ensures that all of the numbers in the available numbers list are always only unused numbers.
You may use a HashSet to store the numbers and make sure there are no duplicates. Here's an example:
HashSet<int> numbers = new HashSet<int>();
Random r = new Random();
for (int i = 0; i < 40; i++)
{
int temp;
do
{
temp = r.Next(0, 100);
} while (numbers.Add(temp) == false); // If the `.Add()` method returns false,
// that means the number already exists.
// So, we try to generate another number.
Console.WriteLine(temp);
}

C# - Random number with seed

I have this code:
var rand = new Random(0);
for(int i = 0; i < 100; i++)
{
Console.WriteLine(rand.Next(0, 100));
}
And program should give me 100 times the same number (because seed is the same), but it gives different numbers...
Why?
Edit:
When I will do
for(int i = 0; i < 100; i++)
{
Console.WriteLine(new Random(0).Next);
}
That returns the same number every time. That means, seed is changing? If yes, how? Is it increasing?
It should not give you 100 same numbers but it should give you exactly the same 100 numbers each time you restart the app.
Seed is used to make random predictable. Imagine multiplayer game where you want something to be random. But you want to make sure that this random behaves the same for each player/client. And seed is the way to go here.

For loop advancing too quickly without generating random strings properly [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 6 years ago.
So I coded a quick program to test how much difference it would make (in terms of processing speed) to check a boolean inside a foreach statement compared to checking it in a conditional statement outside of the loop. To test this I made a function generate random strings and add them to a list, but the for loop that generates the strings seems to advance too quickly without generating different strings in ever repetition. To fix this I added a Thread.Sleep(15) (15 milliseconds seems to be the minimum required to generate a different string in every repetition).
My question is this: is it possible to fix this issue without a Thread.Sleep(15)? Waiting 15 milliseconds between every repetition makes it so that the program takes a way bigger amount of time to run, which makes it highly unpractical for it's purpose (if I want to get statistically relevant data I'd have to run it around 10 thousand times for each option (the "good" and the "bad" way)). Here's the for loop in question:
for (int i = 0; i < 1000; i++) {
var stringChars = new char[8];
var random = new Random();
for (int n = 0; n < stringChars.Length; n++)
{
stringChars[n] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
data.Add(finalString);
Thread.Sleep(15);
}
The problem you are getting is that you are recreating the Random class each time you iterate the loop.
The reason this is a problem is because the default seed for the Random class is the current system timestamp, which on repeated iterations could well be the same value.
Creating the Random outside of the for loop will ensure that a pseduo-random sequence is generated as you would expect.
Try this:
var random = new Random();
for (int i = 0; i < 1000; i++) {
var stringChars = new char[8];
for (int n = 0; n < stringChars.Length; n++)
{
stringChars[n] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
data.Add(finalString);
}

Why is there a strong correlation between random number and correct guesses?

In trying to test whether knowing the history of a random number could help predict the future results, I found a strong, unexpected correlation between the average of the number generated, and the number of correct guesses.
The test was supposed to simulate flipping a coin (heads = 0, tails = 1) and if previous attempts were biased towards heads then guess tails and vice versa.
Why is the sum of the generated numbers always nearly equal to the number of correct guesses in the following LinqPad program?
void Main()
{
var rnd = new Random();
var attempts = 10000000;
var correctGuesses = 0;
long sum = 0;
decimal avg = 0.5m;
for (int i = 0; i < attempts; i++)
{
var guess = avg < 0.5m ? 1 : 0;
var result = rnd.Next(0, 2);
if (guess == result)
{
correctGuesses += 1;
}
sum += result;
avg = (decimal)sum/(decimal)attempts;
}
attempts.Dump("Attempts");
correctGuesses.Dump("Correct Guesses");
avg = (decimal)sum / (decimal)attempts;
avg.Dump("Random Number Average");
}
Have a made an error in the code? Is this a natural relationship? I expected the averages to converge at 0.5 as I increased the number of attempts because the distribution is fairly even - I tested this with 10bn calls to Random.Next(0,2) - but I did not expect the sum of generated numbers to correlate to the number of correct guesses.
Your error is this line:
avg = (decimal)sum/(decimal)attempts;
Makes no sense to divide the sum (based over i to that point) by attempts. Divide by i (EDIT: more precisely i+1) instead for avg to give you something meaningful.
The Random class, without a seed, generates a random number using the current time as seed, meaning that a call of the rnd.Next method in your cycle will result in the same number several times over, depending on how fast your machine goes through the cycle.

Generating multiple random numbers

I want to generate 25 unique random numbers and list them in a console. The numbers should be atleast 10 characters long. Any easy way to do that?
Try building the numbers up as strings, and use a HashSet to ensure they are unique:
Random random = new Random();
HashSet<string> ids = new HashSet<string>();
while (ids.Count < 25)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; ++i)
{
sb.Append(random.Next(10));
}
ids.Add(sb.ToString());
}
Example output:
7895499338
2643703497
0126762624
8623017810
...etc...
The class HashSet is present in .NET 3.5 and newer.
The problem lies a little in "25 unique random". Displaying 25 random numbers is as easy as
Random r = new Random();
for(int i=0; i<25; i++)
Console.WriteLine(r.Next(1,100).ToString());
These are not necessarily unique, though. If you do not want to allow duplicates, you need to store previously generated numbers somehow, and roll again if you hit an old one.
Be aware that you change the probability distribution of your generated numbers this way.
Edit: I've just noticed that these numbers should be ten characters long. Since 9,999,999,999 exceeds Int32.MaxValue, I'd suggest using Math.Floor(r.NextDouble() * 10000000000 + 1000000000) instead of r.Next(1,100).
Since your numbers are that long, you should not need to worry about duplicates. They are very very unlikely.
There is a big different between Randomness and Uniqueness.
So if you need really unique numbers you have to make sure that you save somewhere all already created numbers and check if your newly created one isn't within this list or you have to provide some algorithm that ensures that a given number can't created twice.
To get the second part to work you mostly take the date/time of the creation moment, cause the current date/time pair is unique forever. The only problem is how many creations per (milli)second do you have and how many digits are available to store your unique number.
A sample about using 12 digits is made here. Hope this helps.
One simple way is this:
class Test
{
private static void Main()
{
Random rand = new Random();
for (int i = 0; i < 25; ++i)
{
Console.WriteLine(rand.Next(1000000000, int.MaxValue));
}
}
}
This will ensure that the numbers are always 10 characters (digits) long. They will not necessarily be unique however. If you want them to definitely be unique, you'll have to do something like this:
class Test
{
private static void Main()
{
Random rand = new Random();
var generatedSoFar = new HashSet<int>();
for (int i = 0; i < 25; ++i)
{
int newRand;
do
{
newRand = rand.Next(1000000000, int.MaxValue);
} while (generatedSoFar.Contains(newRand)); // generate a new random number until we get to one we haven't generated before
generatedSoFar.Add(newRand);
Console.WriteLine(newRand);
}
}
}
If you want to be able to have more than ten digits, you generate the number of digits randomly between 10 and your max number of digits. Then generate each digit (or group of digits) randomly in a StringBuilder or List. You can use the same HashSet method I used above to ensure uniqueness.
Random rnd = new Random(table);
for(int i = 0; i < 25; ++i) {
Console.WriteLine("{0}", rnd.Next(50, 50+i)
}

Categories

Resources