CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Brendan Tompkins [MVP]

Blog First. Ask Questions Later.

This is like, so random! Some Randomness from System.Random

If you want a true random number generator, you will want to look beyond System.Random, to the RNGCryptoServiceProvider in the .NET Framework. In fact, there's a good article here that shows how to get a strong password using this method.

But how do you ensure randomness using the System.Random class? 

Creating truly random numbers can be tricky, especially if you need to create a series of random numbers repeatedly.  It’s easy to misunderstand, in fact, you really can’t even trust the code samples from MSDN Documentation for the System.Random Constructor.  Here’s the crux of this issue.

If your application requires different random number sequences, invoke this constructor repeatedly with different seed values. One way to produce a unique seed value is to make it time-dependent. For example, derive the seed value from the system clock.

However, if your application runs on a fast computer the system clock might not have time to change between invocations of this constructor; the seed value might be the same for different instances of Random. In that case, apply an algorithm to differentiate the seed value in each invocation.

The documentation goes on to show some code that supposedly will generate some random numbers, by calling Thread.Sleep(1).  However, this won’t work!  It may work in their example, but in fact, the only reason I think this works in the MSDN Documentation example is by chance!  They just happen to be using enough cpu cycles in a loop (and thus getting a new, unique timer tick) to make the example work! Consider the following code:

 

    static internal string RandomString(int size)

    {

      Thread.Sleep(1);

      Random rand = new System.Random();

 

      StringBuilder builder = new StringBuilder();

 

      for(int i=0; i<size; i++)

      {

        char ch = Convert.ToChar(Convert.ToInt32(26 * rand.NextDouble() + 65)) ;

        if(ch < 0x5B || ch > 0x60) builder.Append(ch);

      }

 

      return builder.ToString();

    }

 

If you run this test below, it fails (and not just because of the by chance occurance of two truly random strings actually being equal), but because Thread.Sleep(1) isn’t long enough to generate a new random seed for the default System.Random() constructor.

    public class RandomStringObject

    {

      public RandomStringObject()

      {

        this.s = RandomString(20);

      }

 

      private string s;

 

      public string S

      {

        get { return s; }

      }

    }

 

 

    [Test]

    public void TestRandomString()

    {

      ArrayList randomStringsObjects = new ArrayList();

      for(int i = 0; i < 2000; i ++)

      {

        RandomStringObject rso = new RandomStringObject();

        Assert.IsFalse(randomStringsObjects.Contains(rso.S));

        randomStringsObjects.Add(rso.S);

      }

    }

In order to get this test to pass, you have to increase the Thread.Sleep time, but isn’t really a good solution, since it’s bound to introduce slowness into your code.  A better solution, is to create the Random object once, and simply use it each time you generate a new random number, see these posts here and here for an overview of this.   Unfortunately, this isn’t possible from a static contex (within a constructor for example) since it won’t have access to the object, unless of course you pass in a reference to the Random object, which isn’t really a good solution either. 

A perfect solution?  Well, I’m not sure if there is one, but I did some experimentation, and found that the Hash Code of a Guid (generated by using Guid.NewGuid().GetHashCode()) creates a fairly unique integer, and we can use this as our random seed.

    static internal string RandomString(int size)

    {

 

      Random rand = new System.Random(Guid.NewGuid().GetHashCode());

 

      StringBuilder builder = new StringBuilder();

      char ch ;

      for(int i=0; i<size; i++)

      {

        ch = Convert.ToChar(Convert.ToInt32(26 * rand.NextDouble() + 65)) ;

        if(ch < 0x5B || ch > 0x60) builder.Append(ch);

      }

 

      return builder.ToString();

    }

This code above does a much better job generating the random strings.  Is this useful in any way? I’m not quite sure. Like I said, you'll want to use RNGCryptoServiceProvider for security purposes, like password generation.  I guess the big take away from all this is that you may think you’re code is being random, when it’s actually being very un-random, so watch out!  That is so random!

Brendan



Comments

Matt Ranlett said:

The Atlanta C# User Group (www.atlantacsharp.org) just had a meeting where one member used the System.Random namespace to generate some random numbers. We were easily able to see how those numbers, based on the system clock, weren't really random. I'm going to forward this article to him so he has it for future reference. Thanks for the great post.

http://www.devcow.com/weblogs/PermaLink,guid,ac33ae18-d4c6-402e-a646-a729c160afcc.aspx
# March 9, 2005 9:05 PM

Sam said:

That's a pretty inventive solution! I like it a lot better than the ThreadSleep. Timing games are such a pain.
# March 10, 2005 6:32 AM

Richard Dudley said:

RFC 1750 - Randomness Recommendations for Security (http://www.faqs.org/rfcs/rfc1750.html) covers some of this also, including the problem with clock ticks as seeds. They also have a section on DoD's recommendations for password generation, which talks about various seed values.

One way I've generated different seeds in the same module is to take the clock ticks, and use the left 3 characters as one seed, left 5 as another seed, right 4 as another seed, right 6 as another, ...
# March 10, 2005 12:15 PM

TrackBack said:

# March 10, 2005 1:02 PM

TrackBack said:

# March 10, 2005 1:04 PM

me said:

Excellent simple solution. I can now do 3000 or so more simulations in the same amount of time!
# June 29, 2005 12:14 AM

Steve Taylor said:

This profoundly improved my speed on a simulation. Thank you.
# July 5, 2005 5:43 PM

Jon Galloway said:

Code Puzzle #2 posed the following task: Write a simple function which generates fake but passable surnames

# January 13, 2007 12:54 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Brendan Tompkins

Brendan has been programming with .NET since the first public beta and is owner and operator of Port Technology Services, a consultancy company providing .NET application development services to the Maritime industry. In July, 2007, he was awarded the Microsoft MVP award for ASP.NET. He's also a proud co-founder of failed .COM startup Intrinsigo, and has had a hand in the failure of numerous other businesses. He currently runs CodeBetter.Com and Devlicio.us, and lives in Norfolk, Virgina with his wife Tiara and son Ian.

View Brendan's profile on LinkedIn

Check out Devlicio.us!

Our Sponsors

Free Tech Publications