I am using .NET to create an artificial life program and I am using C#'s pseudo random class defined in a Singleton. The idea is that if I use the same random number generator throughout the application, I could merely save the seed and then reload from the seed to recompute a certain interesting run.
public sealed class RandomNumberGenerator : Random
{
private static readonly RandomNumberGenerator instance = new RandomNumberGenerator();
RandomNumberGenerator()
{
}
public static RandomNumberGenerator Instance
{
get
{
return instance;
}
}
}
I also wanted a method that could give me two different random numbers.
public static Tuple<int, int> TwoDifferentRandomNumbers(this Random rnd, int minValue, int maxValue)
{
if (minValue >= maxValue)
throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than minValue");
if (minValue + 1 == maxValue)
return Tuple.Create<int, int>(minValue, maxValue);
int rnd1 = rnd.Next(minValue, maxValue);
int rnd2 = rnd.Next(minValue, maxValue);
while (rnd1 == rnd2)
{
rnd2 = rnd.Next(minValue, maxValue);
}
return Tuple.Create<int, int>(rnd1, rnd2);
}
The problem is that sometimes rnd.Next(minValue,maxValuealways returns minValue. If I breakpoint at this point and try creating a double and setting it to rnd.NextDouble(), it returns 0.0. Anyone know why this is happening?
I know that it is a pseudo random number generator, but frankly, I hadn't expected it to lock at 0. The random number generator is being accessed from multiple threads... could this be the source of the problem?
EDIT : Thanks, the problem ended up being thread safety.
This is the new version of the class.
public sealed class RandomNumberGenerator : Random
{
private static Random _global = new Random();
[ThreadStatic]
private static Random _localInstance;
RandomNumberGenerator()
{
}
public static Random Instance
{
get
{
Random inst = _localInstance;
if (inst == null)
{
int seed;
lock (_global) seed = _global.Next();
_localInstance = inst = new Random(seed);
}
return _localInstance;
}
}
}
The Random class is not thread-safe.
You should make your static instance [ThreadStatic], or protect it with a lock.
If you use only One RNG for multiple threads even if you save the seed, you won't be able to generate the same numbers the next time you launch your application because you won't be sure that the calls to the RNG from the different threads will be in the same order.
If you have a fixed/known number of thread make a RNG per Thread and save each seed.
Forget what I just said if you're 100% sure that each thread will call the RNG with exactly the same order as the last time if you use the same seed.
The idea is that if I use the same random number generator throughout the application, I could merely save the seed and then reload from the seed to recompute a certain interesting run.
You don't actually need a singleton instance of the RNG for this. If you initialize two separate instances of Random to the same seed, they will produce exactly the same sequence.
My advice is, save the seed, but get rid of the singleton.
I don't even have to look up the Random class th know "all instance methods of this class or not thread-safe". That goes for all .NET classes, with a very few exceptions.
So yes, it is the multi-threading. But you haven't mentioned verifying that MaxValue > MinValue either.
Related
I have a SQL column with datatype as Bigint, so when I 'm generating a unique number using C# Random class in a multithreaded environment, I see there are duplicate values instead of having unique, I can see only system GUID is the only option to generate unique Id's, could you please help me to solve this problem.
private Object thisLock = new Object();
public Random a = new Random(DateTime.Now.Ticks.GetHashCode());
private void NewNumber()
{
lock (thisLock)
{
MyNumber = a.Next(0, 10);
}
}
The Random class generates random values, not unique values. In your sample code the maximum number of unique integers is 10 (from 0 to 9). So if you called this method at least 11 times, you would be guaranteed one or more duplicates.
For a database you should use identity columns.
Your code should normally run without error, and I did not find an error. The duplicate numbers may be due to their small range.
You can use the following class to generate random numbers between ranges. Returns a number from the desired range each time.
class UniqueRandom
{
private readonly List<int> _currentList;
private readonly Random _random = new Random();
public UniqueRandom(IEnumerable<int> seed)
{
_currentList = new List<int>(seed);
}
public int Next()
{
if (_currentList.Count == 0)
{
throw new ApplicationException("No more numbers");
}
int i = _random.Next(_currentList.Count);
int result = _currentList[i];
_currentList.RemoveAt(i);
return result;
}
}
create instance from UniqueRandom class and call Next() method in NewNumber() method
UniqueRandom u = new UniqueRandom(Enumerable.Range(0, 10));
private Object thisLock = new Object();
public Random a = new Random(DateTime.Now.Ticks.GetHashCode());
private void NewNumber()
{
lock (thisLock)
{
MyNumber = u.Next();
}
}
The SQL Server Bigint type is equivalent to the C# Int64 (long) type. To generate random long values in C#, look at this question. To ensure that the random number is also unique, add a unique constraint to the relevant datatable column. In case the random value already exists in the database, catch the constraint-violation exception, and try again with a new random value.
Regarding how to use the Random class correctly in a multithreaded environment, check out this question: Is C# Random Number Generator thread safe?
I was hoping there's a built in method in Random for this, but there isn't? So I came up with this function to return the nth instance of a random seed:
public class Program {
static int seed = 123; // This could be anything
static int NextN(int n, int range) // Get the nth instance of seed
{
Random rand = new Random(seed);
List<int> pool = new List<int>();
while( pool.Count< n+1 ){ pool.Add(rand.Next(range)); }
return pool[n];
}
public static void Main()
{
Console.WriteLine(NextN(8,100)); // Return 19 as the 8th value of seed 123 at 100 range.
}}
As you can see, the NextN() function generate the sequence of random numbers first, then return the value of the nth instance. This will perform badly once you're trying to reach a very high instance (like in the millions). Since random always return the same value each time you restart an app, I need to keep track how many times the random seed is accessed between session. Is there a way around this?
I was searching on google for RNGCryptoServiceProvider with examples on how to limit the range between Max and Min, and still get an even distribution. Before I used modulo operator, but sometimes it I get strange values (above Max)...
Anyways this code (credit to unknown) seeds Random with a new seed from RNGCCryptoServiceProvider, everytime the method is called. What do you guys think?
public static int GetRandom(int min, int max)
{
byte[] b = new byte[sizeof(int)];
new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(b);
int i = BitConverter.ToInt32(b, 0);
Random r = new Random(i);
return r.Next(min, max);
}
There is no point in using an encryption class random generator to seed a regular random generator. (By the principle of the weakest link...) Just use a single instance of the random generator, and reuse it:
private static Random rnd = new Random();
public static int GetRandom(int min, int max) {
return rnd.Next(min, max);
}
You'll want to create your RNGCryptoServiceProvider object once and then re-use that object every time you want a new random number. For instance, you can either pass said object into your GetRandom() method or store it in a class-level field.
As far as the RNGCryptoServiceProvider type itself, it generates good numbers on its own, there's no need to create a Random object and pass in a seed. This should give you a very decent distribution:
public static int GetRandom(RNGCryptoServiceProvider rngProvider, int min, int max)
{
byte[] b = new byte[sizeof(UInt32)];
rngProvider.GetBytes(b);
double d = BitConverter.ToUInt32(b, 0) / (double)UInt32.MaxValue;
return min + (int)((max - min) * d);
}
It's a better practice to seed your random number generator just one time in your application.
I suggest you create a static class for random number generation. The random generation object can yield even distribution just by normal usage. I don't know whats the benefit of seeding the generator with RNGCryptoServiceProvider. I prefer using the time as seeding method as usual. Therefore the following code is my suggestion:
int randomNumber=Rand.get(min,max);
public static class Rand
{
private static Random rnd;
static rand()
{
rand=new Random(DateTime.Now.Ticks);
}
public static int get(int min,int max)
{
return rnd.Next(min,max);
}
}
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
c# - getting the same random number repeatedly
Random number generator not working the way I had planned (C#)
I have a method that builds a queue of ints:
public Queue<int> generateTrainingInts(int count = 60)
{
Queue<int> retval = new Queue<int>();
for (int i = 0; i < count; i++)
{
retval.Enqueue(JE_Rand.rInt(2001, 100));
}
return retval;
}
JE_Rand.rInt() is just a function that delegates to a function of the Random class:
public static int rInt(int exclUB, int incLB = 0)
{
Random rand = new Random(DateTime.Now.Millisecond);
int t = rand.Next(incLB, exclUB);
rand = null;
return t;
}
But when I call generateTrainingInts, the same number is enqueued each time. However, if I change rInt to use a static instance of the Random class, instead of a local instance (with function scope as it is defined above), then it appears to work correctly (enqueue random integers). Does anybody know why this happens?
Edit:
Dear Answerers who didn't read my question thoroughly,
Like some of you pointed out, I am looking for a good explanation of why this happens. I am not looking for a solution to the same-number-generated problem, because I already fixed that like I said above. Thanks for your enthusiasm though :) I really just want to understand things like this, because my first implementation made more sense conceptually to me.
You need to keep the same Random object. Put it outside your static method as a static member
private static Random rand = new Random();
public static int rInt(int exclUB, int incLB = 0)
{
int t = rand.Next(incLB, exclUB);
return t;
}
Edit
The reason is the finite resolution of the clock used to initialize Random. Subsequent initializations of Random will get the same starting position in the random sequence. When reusing the same Random the next value in the random sequence is always generated.
Try out the following code and I think you'll see why:
void PrintNowAHundredTimes()
{
for (int i = 0; i < 100; ++i)
{
Console.WriteLine(DateTime.Now);
}
}
The Random objects are getting the same seed over and over. This is because the granularity of the system time returned by DateTime.Now is, quite simply, finite. On my machine for example the value only changes every ~15 ms. So consecutive calls within that time period return the same time.
And as I suspect you already know, two Random objects initialized with the same seed value will generate identical random sequences. (That's why it's called pseudorandom, technically.)
You should also be aware that even if it made sense to instantiate a new Random object locally within your method, setting it to null would still serve no purpose (once the method exits there will be no more references to the object anyway, so it will be garbage collected regardless).
public class JE_Rand
{
private static Random rand= new Random(DateTime.Now.Millisecond);
public static int rInt(int exclUB, int incLB = 0)
{
int t = rand.Next(incLB, exclUB);
return t;
}
}
I have a Random into a class which aims to generate random sequences in different contexts: this is the result of a porting from Java code.
In the Java version everything works fine since the java.lang.Random class has the method setSeed, which permits the change of the seed value dynamically.
Random rnd = new Random();
...
rnd.nextInt();
...
rnd.setSeed(seedValue);
This generates a consistent result, since each time the seed value is set, the result is random.
Unfortunately in C# the behavior is much different, since the Random class needs the seed to be set at construction:
Random rnd = new Random(seedValue);
...
rnd.Next();
...
So I have to build a new Random instance each time with the given seed, which in some spare cases generates the same value of a previous call.
Is it a way to set the seed of a Random instance in C# dynamically, without losing the consistency of the instance globally?
Thank you very much!
Typically I create a single instance of Random for my application and after setting the seed on instantiation can rely on each call to Next giving me a new random number. The trick is to make sure the seed is as random as possible. The use of Random in a C# app is a good example of where a Singleton is a good fit.
There are a variety of ways to get differing strengths of randomness in your seed and there are some good SO questions dealing with that.
The example below is the approach I use.
m_randomURL = "https://www.random.org/cgi-bin/randnum?num=1&min=1&max=1000000000";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_randomURL);
StreamReader stIn = new StreamReader(req.GetResponse().GetResponseStream());
Random rand = new Random(Convert.ToInt32(stIn.ReadToEnd()));
random.org uses atmospheric noise to generate the randomness and is apparently used for lotteries and such.
First of all, I wouldn't expect to have setSeed called more than once on a Random during runtime. FreeCell does it so that you can "load" game instances by writing down the seed that was used.
If you change seeds, it should be like resetting the Random instance and thus there should be no conflict if you reinstanciate it. Random is just a wrapper on an underlying algorithm.
If you want to receive different results each time (even if you USE setSeed), you might try this:
class MyRandom {
private Random random = new Random(DateTime.Now.Ticks);
public void setSeed(long seed) {
random = new Random(seed * this.random.next());
...
public long next() {
return random.next();
}
class MyClass {
private MyRandom random = new MyRandom();
public void Test() {
random.setSeed(seedValue);
int x = random.next();
random.setSeed(seedValue);
int y = random.next();
// x,y will be different in most of the cases now
}
}
This will change pre/postconditions of how seeds for random generators should work but might work for you.
try to wrap the Random instance, as pseudocode:
class MyRandom {
private Random random;
public void setSeed(long seed) {
random = new Random(seed);
...
public long next() {
return random.next();