Bruno Klein
Bruno Klein

Reputation: 3367

Random class generating same sequence

I have a method which I am using to generate random strings by creating random integers and casting them to char

public static string GenerateRandomString(int minLength, int maxLength)
        {
            var length = GenerateRandomNumber(minLength, maxLength);

            var builder = new StringBuilder(length);

            var random = new Random((int)DateTime.Now.Ticks);

            for (var i = 0; i < length; i++)
            {
                builder.Append((char) random.Next(255));
            }

            return builder.ToString();
        }

The problem is that when I call this method frequently, it is creating the same sequence of values, as the docs already says:

The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random.

As you can see I am making the seed time dependent and also creating a new instance of Random on each call to the method. Even though, my Test is still failing.

[TestMethod]
        public void GenerateRandomStringTest()
        {
            for (var i = 0; i < 100; i++)
            {
                var string1 = Utilitaries.GenerateRandomString(10, 100);
                var string2 = Utilitaries.GenerateRandomString(10, 20);
                if (string1.Contains(string2))
                    throw new InternalTestFailureException("");
            }
        }

How could I make sure that independently of the frequency on which I call the method, the sequence will "always" be different?

Upvotes: 1

Views: 821

Answers (3)

Nikhil Agrawal
Nikhil Agrawal

Reputation: 48568

dasblinkenlight has given why this is happening.

Now you should do this to overcome this problem

public static string GenerateRandomString(Random random , int minLength, 
                                                  int maxLength)
{
    var length = GenerateRandomNumber(random , minLength, maxLength);

    var builder = new StringBuilder(length);   

    for (var i = 0; i < length; i++)
         builder.Append((char) random.Next(255));

    return builder.ToString();
}

public void GenerateRandomStringTest()
{
    Random rnd = New Random();
    for (var i = 0; i < 100; i++)
    {
        var string1 = Utilitaries.GenerateRandomString(rnd, 10, 100);
        var string2 = Utilitaries.GenerateRandomString(rnd, 10, 20);
        if (string1.Contains(string2))
            throw new InternalTestFailureException("");
    }
}

Upvotes: 1

khellang
khellang

Reputation: 18102

You're effectively doing the same as Random's default constructor. It's using Environment.TickCount. Take a look at the example in this MSDN documentation for the Random constructor. It shows that inserting a Thread.Sleep between the initialization of the different Random instances, will yield different results.

If you really want to get different values, I suggest you change to a seed value that's not time-dependent.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726669

Your test is failing because the GenerateRandomString function completes too soon for the DateTime.Now.Ticks to change. On most systems it is quantized at either 10 or 15 ms, which is more than enough time for a modern CPU to generate a sequence of 100 random characters.

Inserting a small delay in your test should fix the problem:

var string1 = Utilitaries.GenerateRandomString(10, 100);
Thread.Sleep(30);
var string2 = Utilitaries.GenerateRandomString(10, 20);

Upvotes: 3

Related Questions