11

I'm looking at generating a random number between 1 and 5 million. The process doesn't have to be quick (although it would 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.

This will be used to select a winning ticket.

7
  • 5
    Clearly and precisely define "as random as possible". To get a signal that is actually "as random as possible" you need a source of entropy -- the seed -- that has more bits of entropy than the random item generated from that seed. So, if you already have a variety of data sources for the seed, and they are high-entropy, then you're already done. Just extract 24 bits from your source of entropy, and that gives you a number between 0 and 16 million that is as random as possible given your source of entropy. Commented Feb 14, 2010 at 16:51
  • 2
    Also, it would help tremendously if you described what you're going to be using this random number for. Commented Feb 14, 2010 at 16:52
  • 3
    Re: your update: Now you are no longer in the realm solely of math and technology, but in the realm of legal regulations. Most of the people reading this are not lawyers familiar with the laws regarding what characteristics a device which chooses the winner of a lottery must possess. I would recommend consulting with a lawyer and a statistician before you spend more time pursuing a technical solution. Certainly no simple "pseudo random" solution is going to be acceptable; one can easily work out what the next winning number is from the previous ones with a PRNG. Commented Feb 15, 2010 at 0:48
  • 8
    The fact that you cannot see how it would be worked out does not logically imply that no one can see how it can be worked out. Pseudo-random number generators are called "pseudo-random" because they are not random. They are predictable; given information about their past output you can work out their likely future outputs. Furthermore, it is not enough that a RNG be unpredictable; it must also be unbiased. Commented Feb 17, 2010 at 5:54
  • 1
    @CodeInChaos: Right, that's why I said that no simple pseudo-random solution -- like calling Random.Next -- is going to work. A crypto-strength randomness solution is likely to be sufficiently random to prevent fraud, but still might not meet the legal requirements. Commented Jul 16, 2011 at 15:12

8 Answers 8

17

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.

Sign up to request clarification or add additional context in comments.

2 Comments

See here connect.microsoft.com/VisualStudio/feedback/details/634761/… It is coded incorrectly and so may not be good enough
@evolvedmicrobe: Having run a bunch of statistical tests on a version of System.Random with a patch fixing that particular bug, it's not clear to me that there aren't other things about the RNG that should be more worrying. Certainly, it has several different issues: github.com/dotnet/corefx/issues/23298
7

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.

5 Comments

RNGCryptServiceProvider works on filling byte arrays so you'd need to convert back to an int and check it's in the right range
+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 Which is one more reason not to use System.Random since their implementation of Next(...) are biased(They don't seem to use % but the numbers are not equally likely.)
@CodeInChaos: But System.Random can not be used for cryptographic numbers, which is what my answer is about.
Of course. But it's even flawed for non cryptographic numbers since it has a flaw similar to the one @devstuff mentioned.
5

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).

5 Comments

The C# library is not based on Knuth's method, they goofed coding it
@evolvedmicrobe: That's what their documentation says. Do you have a citation or some evidence to prove otherwise?
yes, they attempted it here and I have verified myself by decompiling: connect.microsoft.com/VisualStudio/feedback/details/634761/…
@evolvedmicrobe: Fair enough, although I hardly think such a minor discrepancy makes any difference as to the substance of this answer (or Chris's, for that matter - either a PRNG meets the requirement or it doesn't, makes no difference what the period is).
@aeronaught not saying it affects the substance of the answer, and the original question was so lacking in specific requirements who knows what the answer to that is. But people reading the post (or the MSDN documentation) might have thought the speedy one was based on Knuth, which it wasn't, so thought I would save others from being tripped up the way I was.
5

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...

1 Comment

"more..." link is now broken.
4

To generate a random number, create an object of Random class, and then use Next function of this object to generate a random number. It has many overloads like:

Next(int minimum, int maximum);
Next(int Maximum);

where you can specify the minimum and maximum range between which you want the random number.

Code snippet:

Random random = new Random();
int maxValue = 100;

int r = random.Next(maxValue);

Comments

3

The System.Random class is very problematic and isn't a good fit with the requirement. In theory, it should provide better results than many other pseudo-random generators out there. It is a direct and literal port of example C code for a Lagged Fibonacci Generator (LFG) provided on page 283 of the second edition of 'Numerical Recipes in C' (the code was re-written in later editions). LFGs use a better algorithm than Linear Congruential Generators (LCGs) used is many other libraries (e.g., Java).

Unfortunately, Microsoft's implementation of System.Random class has a bug in it. See http://connect.microsoft.com/VisualStudio/feedback/details/634761/system-random-serious-bug for more information. It seems someone accidently typed in '21' when the meant to type in '31'. This compromises the algorithm's pseudo-random characteristics. The link includes an explanation from MS as to why they feel unable to fix the error at this stage.

2 Comments

Thanks for the detailed response. We ended up using a hardware rng but thanks for the info and the link!
There's another bug in the mapping of negative seed values. These are mapped to their absolute value, but if the seed is int.MinValue it is mapped to int.MaxValue. This means that there are three input seeds that map to int.MaxValue and only one that maps to zero, while every positive integer other than int.MaxValue corresponds to two input values. This implies that there is one sequence that has a 50% higher probability of being chosen and one that has a 50% lower probability. Unfortunately the connect link is dead.
1

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: 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).

Comments

-1

.NET's Random should be fine for this:

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

int randomNumber = random.Next(1, 5000000);

4 Comments

This only works for a local variable, that's an accident waiting to happen.
Should be int randomNumber = random.Next(1, 5000001); as the .Net method returns a number inclusive of the lower limit but exclusive of the upper limit.
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.
this only offers 1000 different seeds, changes only rarely,... This is even worse than just using new Random()

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.