This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 3 years ago.
for (int i = 1; i < 10; i++)
{
number = randomNumber();
if (!straightLine.Contains(number))
{
straightLine.Add(number);
}
}
public static int randomNumber()
{
Random random = new Random();
return random.Next(1, 100);
}
when I debug it works fine but when I run the program it gets 1 random number and that's it. so the problem is that the random Number method is only called once (when I don't debug then it calls it every time)
what can I do?
germi's answer is slightly misleading as it implies that any repeated instantiation of a new Random will produce the same sequence of values. This isn't quite correct, because your debug code works as you expect.
The documentation for Random says that the Random number generator is seeded from the system clock if you dont pass a seed value. https://learn.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=netframework-4.8
The reason it works in debug is that debugging code is very slow (you're literally taking hundreds of milliseconds to step through the code a line at a time) and the clock has time to change in between runs of the loop.
When your code is run at full speed it runs so quickly that the system clock simply won't have changed to a new milliseconds value, so your repeated making of a new Random will result in it being seeded with the same value from the clock
If you were to insert some delay in the code such as Thread.Sleep(1000) in the loop then it would work. If you were to run the loop a million times it would take long enough to work through that the clock would eventually change - a million iterations might take long enough for a small handful of values to come out of the Random
The recommendation for a solution is sound though; make one new Random somewhere outside of the loop and then repeatedly call it. You could also seed the Random with something that is unique each time (like the value of i), though you should bear in mind that providing a particular seed will guarantee that the same random number comes out of it when you call Next. In some contexts this is useful, because you might want a situation where you can provide a certain value and then see the same sequence of random numbers emerge. The main thing to be mindful of is that by default the Random starts it's sequence based on the clock; two different computers with different time settings can theoretically produce the same random numbers if their clocks are reading the same at the moment the Random is created.
Repeatedly instantiating a new Random instance will lead to the same number being generated, since the seed will be the same.
The solution is to have one instance of Random in the class that generates the values:
var random = new Random();
for (int i = 1; i < 10; i++)
{
number = random.Next(1,100);
if (!straightLine.Contains(number))
{
straightLine.Add(number);
}
}
Note that this behavior only exists in .NET Framework, .NET Core will produce different values even across multiple Random instances created in quick succession.
Related
I am making a simple game in C# and using Random class to generate a random number every 2 seconds, but it gives numbers that I can guess in advance because it increments by a certain number each time.
private int RandomNumber;
//This Timer function runs every 2 seconds
private void TmrGenerateRandomNum(object sender, EventArgs e)
{
Random r = new Random();
RandomNumber = r.Next(50, 200); //Trying to get random values between 50 and 200
Label1.Text = RandomNumber.ToString();
}
This is literally the only code I have, and I am displaying the value each time through Label1. The problem is, for example, if I first get 52, the next "randomly"-generated value is 71 or 72, and the next one is 91 or 92, and the next one is 111 or 112. As you can see, it is incrementing by 20ish. Then it suddenly gets a real random value again like, say, 163. But then the next generated number is 183, again incremented by 20. Since 183+20 exceeds the range, it gets a real random value again, say 83. But the next number generated is again 103, or 104, and then 123 or 124...
This is not "Random" because you can tell around what number the next one is going to be... and this is driving me crazy.
Do you know why it does this, and is there a fix for this?
Random numbers use a seedvalue to start the sequence. If you give nothing, it takes to current datetime.now value. if you supply the same value (like 3842) you will get the same sequence of random values guaranteed. Your series seemed to be very closely related so you see the same values. All this can be read in the documentation on msdn, see Instantiate pseudo random :
Instantiating the random number generator
You instantiate the random number generator by providing a seed value (a starting value for the pseudo-random number generation algorithm) to a Random class constructor. You can supply the seed value either explicitly or implicitly:
The Random(Int32) constructor uses an explicit seed value that you supply.
The Random() constructor uses the system clock to provide a seed value. This is the most common way of instantiating the random number generator.
If the same seed is used for separate Random objects, they will generate the same series of random numbers. This can be useful for creating a test suite that processes random values, or for replaying games that derive their data from random numbers. However, note that Random objects in processes running under different versions of the .NET Framework may return different series of random numbers even if they're instantiated with identical seed values.
Source: https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx#Instantiate
You find more information and even methods to "better" cryptographical random methods linked above the source I cited.
While true random numbers are relatively difficult to generate, you should be able to get much better results than you are. The problem you're likely having right now, as suggested by comments, is that you should not be "starting over" every time the function is called. As a test, you can try passing some value like 5 as a parameter to the Random constructor. Then you will notice your results are really not random. To fix this, as the comments suggest, you should move the construction of the Random object somewhere global so that the randomness can "build" on itself over time instead of always being reset. Once you confirm that you can get different values with repeated calls, then remove the parameter to the Random constructor so that you don't get the same sequence of random numbers every time you restart your program.
More of an in-depth explanation:
Basically, it's pretty much impossible to generate truly random values in a computer, all of the random values you get are pseudo random and are based off of values like:
User input, like how many keys were pressed in the last 2 minuts
Memory usage, how many KB of memory is being used at this very moment
The most common one: Using the current time in mili seconds to generate a "seed" that's used to generate a series of numbers that are mathematical as randomized as possible
This is where the problem comes from. For example, if you were to have the following code
Random r1 = new Random();
Random r2 = new Random();
Console.WriteLine(r1.next())
Console.WriteLine(r2.next())
Miraculously, you will always get the same number from r1 and r2 despite them being two separate instances. It's because the code block is execute in a time window of <1 ms, which gives these two random number generators the same seed, thus they will generate the same list of numbers.
In your case, the number generator is instantiated every 2 seconds, thus they get an incrementing seed. It's hard to say if that will result in an incrementing starting number, but it might be a start.
So instead, try initializing a single Random() and always call the .next() function on it, and you should be getting a much more random list of numbers
The best you can do is use a CPRNG or Cryptograph Psudo Random Number Generator, it does not need to be seeded by tyhe user and in generally continnualy updates with system events.
To generate a cryptographically secure random number use the RNGCryptoServiceProvider class or derive a class from System.Security.Cryptography.RandomNumberGenerator.
See MSDN Random Class.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 8 years ago.
for (int i = 1; i <= 55; i++ )
{
System.Random myRandom = new System.Random();
//int myInt; 3 lines just alternate method
//myInt = myRandom.Next();
//System.Console.WriteLine(myInt);
System.Console.WriteLine(myRandom.Next());
Thread.Sleep(15); // if less, trouble
}
I kept getting multiples of the same number, up to twenty at a time, instead of each consecutive number being different. For some reason I added the sleep statement and it works if the value is 15 or greater. In fact, if you increment the sleep argument value, you can 'select' how many consecutive repeated numbers you get. Setting a range made no difference. Is the loop faster than the random number generator? This is not serious, I am working through the book "Essential C# 5.0". I looked at least fifty "random" questions, but none covered this phenomena. The three commented lines are a different way to do the same thing, I did not execute both in the same build.
The problem lies in this line:
System.Random myRandom = new System.Random();
It should be outside the for-loop. Why? Because it generates a random seed based on the timing information, and as you create them one after another, they each get the same seed. When you make the thread sleep in-between the iterations, the time changes enough so that the next Random gets a different seed value.
Try this instead:
System.Random myRandom = new System.Random();
for(int i = 1; i <= 55; i++)
{
// Here be the rest of the code
}
Now, the Random object is created just once, getting its seed value just once.
I wrote this class to generate a random code, it shouldn't create any two repetitive number.
I want to know, in this code, how much it possible that we have collision?
public string MyRandom()
{
Random r = new Random();
int x = r.Next(1000);//Max range
PersianCalendar pc = new PersianCalendar();
string _myrandom = pc.GetMonth(DateTime.Now).ToString() + pc.GetDayOfMonth(DateTime.Now).ToString() + pc.GetHour(DateTime.Now).ToString() + pc.GetMinute(DateTime.Now).ToString() + pc.GetSecond(DateTime.Now).ToString() + pc.GetMilliseconds(DateTime.Now).ToString() + x.ToString();
return _myrandom;
}
If we do
List<string> s = new List<string>();
for(int i = 0; i < 100; i++)
{
s.Add(MyRandom());
}
Why?
When random class is created in a loop, you can get duplicate random numbers. More Info
Solution:
Create Random instance outside loop.
It is safer to use more stronger methods such as RNGCryptoServiceProvider which you can find several samples of its usage. Generally, pure random generation is not possible is very high concurrency loads, but reduce its probability to a reasonable amount.
Well first, because you are using the date in the way that you are, then there is only one possible millisecond per year where the _myrandom string could possibly be repeated.
Within that millisecond each year, the odds of hitting a random string you have already generated are down to the variable x, and related directly to how many other random strings you have made in that millisecond (and the previous milliseconds of each previous year). If, for example, you were to have made 10 random strings last year in that millisecond and 4 the year before, the chances of duplication this year are 14:999, which is a chance of about 1.4%.
Of course, if you make 1000 strings per millisecond, the chance of duplication is 100%.
In fact, the chances of duplication are slightly higher, due to the fact that the C# Random number generator doesn't produce a true random number. It's a pseudo-random number, so the chances of a collision are higher.
I see that you've written: "this generator is using for naming photos which uploaded in my application" in the comments above, which makes it unlikely that you'll be making 1000+ names per millisecond. Generally, whenever you are using a random number generator in this way, it's a good idea to just put in some error checking in 1 of two ways:
1. offensive or 2. defensive.
Offensive would be waiting for the error (two identical file names) to happen and then dealing with it (maybe running your random generator again until the error isn't thrown). Defensive would be to check all of the filenames in the file, or keep a list of them all, to check that your new filename isn't the same before you even try to save it. This is more watertight (because you aren't relying on an error to be thrown) but far more computationally expensive.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 9 years ago.
When I executes the following code I'm getting the same color selected always.
static void Main(string[] args)
{
string[] Colors = new string[10] { "Red", "Yellow", "Green", "Blue", "Purple", "White", "violet", "orange", "indigo", "blue" };
for (int i = 0; i < 13; i++)
{
Random rnd = new Random();
int code = rnd.Next(0, 9);
string Color = Colors[code];
Console.WriteLine(Color);
}
Console.ReadLine();
}
But if ` Random rnd = new Random();' is created outside the loop, then the result is unique. If the loop executes in faster rate then the output will be the same. Suppose I do some Database insert operation in the for loop the result will be a different one (a random one)(step by step execution using break points will also result random selection).
Is it really impossible to supply different seeds for such a small duration?
Random uses current time as a seed. When you create it in loop, it happens so fast that time stays the same for every creation. So seed is the same, and values, generated by Random will be the same too.
Try make random object a static member:
private static Random rnd = new Random();
This prevents building several random objects with a same seed (current time), and prevents producing a same sequence of numbers.
Your loop initializes a new instance of Random with the same seed (current time) upon each iteration. Each instance contains a sequence of various random numbers. The code uses the first number from the sequence, and after the iteration is finished the random object is thrown away, and a new Random object is instantiated. Since the code has been run quite fast, the next random object is created at the same time as the previous one, therefore it has the same seed as that one. The new object contains a sequence of various numbers, but the sequence is the same as the previous one (i.e., they have a same first number, second number, and so forth). Again the code uses the first number from the very same sequence, which results in repetitive numbers.
If you make the Random object a static member, the random sequence is created once, and the code will use the next number (not always the first number) of that sequence, hence you will iterate through the sequence of various random numbers.
If you don't want to make the random object a static member, try to feed its constructor a unique seed. You can make use of your loop variable for this purpose.
If you don't provide a seed, Random will use Environment.TickCount for a seed. In a short loop like this, it's entirely possible that the the whole loop is executed in one tick. So the seed is the same every time, hence your "random" number is, too.
Just use the same random object for the entire loop.
Random is not random in computer programming ;) You can make it "more" random by including a seed or by having a static object containing the random :)
you need to keep the same random object for the reason below:
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 random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated.
http://msdn.microsoft.com/en-gb/library/system.random.aspx
Before I start, I want to point out that I'm pretty sure this actually happened. All my logs suggest that it did.
I'd like to know whether I'm wrong and this is impossible, whether it's just incredibly unlikely (which I suspect), or if it's not that unlikely and I'm doing something fundamentally wrong.
I have 4 instances of the same code running as Windows Services on the same server. This server has a multicore (4) processor.
Here's a summary of the code:
public class MyProcess
{
private System.Timers.Timer timer;
// execution starts here
public void EntryPoint()
{
timer = new System.Timers.Timer(15000); // 15 seconds
timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
timer.AutoReset = false;
Timer_Elapsed(this, null);
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
string uid = GetUID();
// this bit of code sends a message to an external process.
// It uses the uid as an identifier - these shouldn't clash!
CommunicationClass.SendMessage(uid);
timer.Start();
}
// returns an 18 digit number as a string
private string GetUID()
{
string rndString = "";
Random rnd = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < 18; i++)
{
rndString += rnd.Next(0, 10);
}
return rndString;
}
The external process that receives these messages got confused - I think because the same uid came from two separate processes. Based on that, it appears that the GetUID() method returned the same "random" 18 digit string for two separate processes.
I've seeded the Random class using DateTime.Now.Ticks which I thought would provide protection between threads - one tick is 100 nanoseconds, surely two threads couldn't get the same seed value.
What I didn't account for obviously is that we're not talking about threads, we're talking about processes on a multicore processor. That means that this code can literally run twice at the same time. I think that's what's caused the clash.
Two processes running the same code at approximate 15 second intervals managed to hit the same code inside 100 nanoseconds. Is this possible? Am I on the right track here?
I'd be grateful for your thoughts or suggestions.
To clarify, I can't really use a GUID - the external process I'm communicating with needs an 18 digit number. It's old, and I can't change it unfortunately.
Unless there is some reason you can't, you should look at using a GUID for this purpose. You will eliminate collisions that way.
Per comment: You could use a GUID and a 64-bit FNV hash and use XOR-folding to get your result to within the 59-bits that you have. Not as collision proof as a GUID, but better than what you have.
You don't want random numbers for this purpose, you want unique numbers. I'm with #JP. I think you should look at using GUIDs for your message ids.
EDIT: if you can't use a GUID, then think of a way to get a 64-bit number that is unique and use successive 3-bit chunks of it as an index into a 8-character alphabet (tossing the unused upper bits). One way to do this would be to have a database in which you create an entry for each new message with an auto-incremented 64-bit integer as the key. Use the key and translate it into your 18-character message id.
If you don't want to rely on a database you can get something that works under certain conditions. For example, if the messages only need to be unique during the life of the processes, then you could use the process id as 32 bits of the value and get the remaining 22 required bits from a random number generator. Since no two processes running at the same time can have the same id, they should be guaranteed to have unique message ids.
There are undoubtedly many other ways that you could do this if your situation doesn't fit into one of the above scenarios.
Try using this function for the seed, in place of DateTime.Now.Ticks:
public static int GetSeed()
{
byte[] raw = Guid.NewGuid().ToByteArray();
int i1 = BitConverter.ToInt32(raw, 0);
int i2 = BitConverter.ToInt32(raw, 4);
int i3 = BitConverter.ToInt32(raw, 8);
int i4 = BitConverter.ToInt32(raw, 12);
long val = i1 + i2 + i3 + i4;
while (val > int.MaxValue)
{
val -= int.MaxValue;
}
return (int)val;
}
This basically turns a Guid into an int. You could theoretically get duplicates, but it's cosmically unlikely.
Edit: or even just use:
Guid.NewGuid().GetHashCode();
Using DateTime.Now.Ticks, on the other hand, almost guarantees a collision at some point. It's very common in Windows programming to have a timer's resolution specified in units that are far beyond the timer's actual accuracy (I first ran into this with Visual Basic 3.0's timer control, which was set in milliseconds but only actually went off 18 times a second). I don't know this for sure, but I bet if you just ran a loop and printed out DateTime.Now.Ticks, you would see the values quantizing around 15ms intervals or so. So with 4 processes going it's actually really likely that two of them would end up using the exact same seed for the Random function.
Since the Guid-based GetSeed function has a super-tiny chance of producing duplicates, ideally you'd want to create some sort of bank of pre-calculated unique numbers. However, since you're talking about separate processes here, you'd have to come up with some way of caching the values where all the processes could read them, which is a bother.
If you want to worry about cosmically unlikely events, buy lottery tickets.
Another way to accomplish this is to not use the Random class as it is fraught with issues like this. You can accomplish the same functionality (a random 18 digit number) using the cryptographic quality random number generator available in System.Security.Cryptography.
I have modified your code to use the RNGCryptoServiceProvider class to generate the id.
// returns an 18 digit number as a string
private string GetUID()
{
string rndString = "";
var rnd = new RNGCryptoServiceProvider();
var data = new byte[18];
rnd.GetBytes(data);
foreach(byte item in data)
{
rndString += Convert.ToString((int)item % 10);
}
return rndString;
}
Yip it can happen, and therefore it did.
You should initialise Random only once, at start-up. If you have many threads starting at the same time, get a copy of DateTime.Now.Ticks and pass it to each thread with a known offset to prevent then initialising on the same time.
I also concur with the GUID idea.
As for your original problem, since Ticks is a long, this statement:
(int)DateTime.Now.Ticks
will cause an overflow. Not sure what kinda nastiness will happen then...