views:

513

answers:

6
+2  Q: 

C# Random Numbers

I'm looking at generating a random number between 1 and 5 Million. The process doesnt have to be quick (Although be good if it was) but it must be as random as possible (I know nothing is random). I have a variety of data sources for the seed.

I'm not sure if the .Net Random class is going to be good enough for this.

Edit: This will be used to select a winning ticket.

+5  A: 

If you need cryptographic random number, go with the System.Security.Cryptography.RNGCryptoServiceProvider class or use the RandomNumberGenerator.Create() factory method to create the default configured random number generator.

Steven
RNGCryptServiceProvider works on filling byte arrays so you'd need to convert back to an int and check it's in the right range
zebrabox
+1 for @zebrabox's comment, plus: if the generated value is out of range, do NOT mod it (% operator) since that may cause a bias for some values. Loop around and generate another value instead.
devstuff
+1  A: 

.Net Random should be fine for this:

var random = new Random(System.DateTime.Now.Millisecond);

int randomNumber = random.Next(1, 5000000);
Michael S. Scherotter
This only works for a local variable, that's an accident waiting to happen.
Hans Passant
Should beint randomNumber = random.Next(1, 5000001);as the .Net method returns a number inclusive of the lower limit but exclusive of the upper limit.
ebpower
It depends on the context where the number is used in if a millisecond is a good enough seed. Slot machines have been hacked this way.
Paco
+4  A: 

The System.Random class probably is good enough:

Pseudo-random numbers are chosen with equal probability from a finite set of numbers. The chosen numbers are not completely random because a definite mathematical algorithm is used to select them, but they are sufficiently random for practical purposes. The current implementation of the Random class is based on Donald E. Knuth's subtractive random number generator algorithm. For more information, see D. E. Knuth. "The Art of Computer Programming, volume 2: Seminumerical Algorithms". Addison-Wesley, Reading, MA, second edition, 1981.

The only thing you have to watch out for is that you don't reuse the same seed too often:

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.

ChrisF
+3  A: 

See Jon Skeet's blog post Revisiting Randomness a very good review of how to use Randomness:

Revisiting randomness
Almost every Stack Overflow question which includes the words "random" and "repeated" has the same basic answer. It's one of the most common "gotchas" in .NET, Java, and no doubt other platforms: creating a new random number generator without specifying a seed will depend on the current instant of time. The current time as measured by the computer doesn't change very often compared with how often you can create and use a random number generator – so code which repeatedly creates a new instance of Random and uses it once will end up showing a lot of repetition.

more...

Metro Smurf
+1  A: 

If you're looking for true random numbers then you should consider using an online random number generator that uses natural phenomenon, such as http://www.random.org, which uses atmospheric noise. True random numbers also make good seeds for psuedo-random number generators.

Sipwiz shows how to use it in C# in his answer: http://stackoverflow.com/questions/677373/generate-random-values-in-c. It's also discussed here: http://www.vcskicks.com/random-number-generator.php.

There's a lot of angles to random number generators. An interesting alternative implementation is ISSAC (ttp://burtleburtle.net/bob/rand/isaac.html), which also contains a good discussion of bias and such, and there's a C# version, too (http://burtleburtle.net/bob/rand/isaacafa.html).

ebpower
+1  A: 

There was actually a really good article I read fairly recently on different types of PRNGs and how they fare in terms of several different randomness tests. Unfortunately, I can't seem to find it now. The gist of it, however, was that the default random number generators in almost every popular programming language are quite naïve and have pretty significant biases.

Another answer already mentions that no PRNG at all, no matter how sophisticated the algorithm, is good enough for cryptographic applications. This is true. Since you mention that this will be used to "select a winning ticket", let's ignore that for now.

The Knuth algorithm used by the .NET System.Random class is optimized mainly for speed, not random distribution. It is "random enough" for many purposes, which most applications never stray too far from, but in the fields of (a) gaming and (b) statistical simulation, most people seem to think that it is a poor choice. It's better than the LCGs that used to be the default in older libraries, but you still don't want to be using it for something like a lotto.

Don't get fooled into thinking that you just use a crypto source, either. The problem with crypto RNGs is that they fill a stream of bytes, but turning this into a single random integer between x and y requires that you do some modular arithmetic (or rounding - same result either way). And if your random range doesn't divide perfectly evenly into whatever power of 2 is defined by the byte length, then you're going to end up with a bias in the lower numbers. The generated data has high entropy, but your result will be biased.

As a simple example, let's just say you get a "perfect" random number from 1 to 10 and now you want to turn that into a random number between 1 and 7. How do you do it? Simply calculating result % 7 will be heavily biased toward the numbers 1-3. There are some ways to reduce the bias when using a crypto RNG but the point I'm trying to make is that crypto RNGs are designed for crypto applications, and using one of those for a Monte Carlo simulation isn't usually the best idea.

As far as I know, the most popular "good" PRNG today, which is used commonly in gaming applications, is the Mersenne Twister. There's a .NET implementation here. This algorithm passes all of the Diehard Tests for random distribution; it shows almost no bias and is a good choice when you are using random numbers for probabilistic and statistical applications.

The GNU Scientific Library also has a number of RNG algorithms and, not surprisingly, the Mersenne Twister is at the top of the list. Some of the others are worth looking at for curiosity's sake, though; RANLUX also scores pretty high on the diehard test IIRC.

Eric is correct with his comment, of course; all of this information is for naught if you don't have specific technical requirements on "how random" you need your random numbers to be. I'm using a definition that would be applicable to a relatively low-impact gambling/gaming application (i.e. not a major registered gambling site with millions of visitors per day - there are stricter rules on randomness for those).

Aaronaught