tags:

views:

529

answers:

3

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!

A: 

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();
dfa
this is what I'm doing at the moment (in the ported version) and doesn't fix the issue: as I said, I should not re-initialize the instance of "random"...
Antonello
+1  A: 

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.

sipwiz
A: 

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.

Marcel J.