简体   繁体   中英

How to force all instances of Random generate same sequence of numbers in different runs?

I'm writing an application for testing an algorithm with random generated inputs. This involves several instances of Random class spread around the code. I need all these instances to generate same inputs in different runs to debug the algorithm when I find an unexpected result. This is the behavior of the apps created with Delphi, unless you manually call Randomize .

I know I can:

  • Provide constant seeds for all created instances.
  • Pass a unique instance, which is created with a constant seed, to all methods that need a random generator.

The reason I prefer not to use any of the above methods is that most of the functions that generate random data are kind of black box functions that are collected here and there on the Internet. Some of them even use several random generators for unknown reasons. I prefer not to mess with these functions unless I really have to.

So, are there any other ways to control all these instances together?

Here's a quick example of a class with two static members, one a "fixed RNG", while the other just a normal "RNG", that you can use from anywhere in your code:

int x = MyRandom.RNG.Next(1, 7);
int y = MyRandom.FixedRNG.Next(1, 7);

Code:

public class MyRandom
{

    private static Random _fixedRandom = new Random(1234);
    private static Random _random = new Random();

    public static Random FixedRNG
    {
        get
        {
            return _fixedRandom;
        }
    }

    public static Random RNG
    {
        get
        {
            return _random;
        }
    }

}

An alternative might be to include an IsRandom property that determines which one gets returned:

public class MyRandom
{

    private static bool _isRandom = false;
    private static Random _fixedRandom = new Random(1234);
    private static Random _random = new Random();

    public static bool IsRandom
    {
        get
        {
            return _isRandom;
        }
        set
        {
            _isRandom = value;
        }
    }

    public static Random RNG
    {
        get
        {
            if (IsRandom)
                return _random;
            else
                return _fixedRandom;
        }
    }

}

Thanks to @Idle_Mind for their suggestion. Here is a more Delphi-like version:

public static class GlobalRandom
{
    private static int _randSeed = 0;
    public static Random RNG { get; private set; } = new Random(_randSeed); // Made accessible for Random extensions
    public static void Randomize() { RNG = new Random(); }
    public static int RandSeed { get => _randSeed;
        set { _randSeed = value; RNG = new Random(_randSeed); } }
    public static int Next() => RNG.Next();
    public static int Next(int minValue, int maxValue) => RNG.Next(minValue, maxValue);
    public static int Next(int maxValue) => RNG.Next(maxValue);
    public static void NextBytes(byte[] buffer) => RNG.NextBytes(buffer);
    public static double NextDouble() => RNG.NextDouble();
}

Use it like:

Console.WriteLine($"Default seed (0):     {GlobalRandom.Next()}");
GlobalRandom.Randomize();
Console.WriteLine($"Unknown seed:         {GlobalRandom.Next()}");
GlobalRandom.RandSeed = 100;
Console.WriteLine($"Constant seed (100):  {GlobalRandom.Next()}");
GlobalRandom.RandSeed = 0;
Console.WriteLine($"Back to default seed: {GlobalRandom.Next()}");

First Run:

Default seed (0): 1559595546
Unknown seed: 1837960504
Constant seed (100): 2080427802
Back to default seed: 1559595546

Second Run:

Default seed (0): 1559595546
Unknown seed: 54655523
Constant seed (100): 2080427802
Back to default seed: 1559595546

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM