|
Introduction
Random number generation is tricky business. Good random number generation algorithms are tricky to invent. Code implementing the algorithms is tricky to test. And code using random number generators is tricky to test. This article will describe SimpleRNG, a very simple random number generator. The generator uses a well-tested algorithm and is quite efficient. Because it is so simple, it is easy to drop into projects and easy to debug into.
Why not just use the .NET random number generator?
For many applications, it hardly matters what random number generator you use, and the one included in the .NET runtime would be the most convenient. However, sometimes it helps to have your own random number generator. Here are some examples.
- When debugging, it's convenient to have full access to the random number generator. You may want to examine the internal state of the generator, and it helps if that state is small. Also, it may be helpful to change the generator temporarily, making the output predictable to help debug code that uses the generator.
- Sometimes it is necessary to compare the output of programs written in different languages. For example, at my work we often take prototype code that was written in R and rewrite it in C++ to make it more efficient. If both programs use their own library's random number generator, the outputs are not directly comparable. But if both programs use the same algorithm, such as the one used here, the results might be directly comparable. (The results still might not match due to other differences.)
- The statistical quality of the built-in generator might not be adequate for some tasks. Also, the attributes of the generator could change without notice when you apply a service pack.
Background
George Marsaglia is one of the leading experts in random number generation. He's come up with some simple algorithms that nevertheless produce high quality output. The generator presented here, SimpleRNG, uses Marsaglia's MWC (multiply with carry) algorithm. The algorithm is mysterious but very succinct. The algorithm passes Marsaglia's DIEHARD battery of tests, the acid test suite for random number generators.
The heart of SimpleRNG is three lines of code. Here is the method that generates uniformly distributed unsigned integers.
private static uint GetUint()
{
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
return (m_z << 16) + m_w;
}
Here m_w and m_z are unsigned integers, the only member variables of the class. It's not at all obvious why this code should produce quality random numbers, but it does.
The unsigned integer is then turned into a double in the open interval (0, 1). ("Open" means that the end points are not included; the method will not return 0 or 1, only numbers in between.)
public static double GetUniform()
{
uint u = GetUint();
return u * 2.328306435996595e-10;
}
Using the Code
The SimpleRNG class has two seeds. These have default values, or they can be specified by calling SetSeed() with one or two arguments. There is also an option to set the seed values from the system clock using SetSeedFromSystemTime(). Once the class is initialized, there is only one public method to call, GetUniform().
Points of Interest
The code to test SimpleRNG is more complicated than SimpleRNG itself. The test code included as a demo uses a statistical test, the Kolmogorov-Smirnov test, to confirm that the output of the generator has the expected statistical properties. If this test were applied repeatedly with ideal random input, the test would fail on average once in every thousand applications. This is highly unusual in software testing: the test should fail occasionally! That's statistics for you. Don't be alarmed if the test fails. Try again with another seed and it will most likely pass. The test is good enough to catch most coding errors since a bug would likely result in the test failing far more often.
History
- 11th April, 2008: Initial post
- 13th April, 2008: Revised article to explain why this generator might be preferable to the built-in generator
| You must Sign In to use this message board. |
|
| | Msgs 1 to 20 of 20 (Total in Forum: 20) (Refresh) | FirstPrevNext |
|
|
 |
|
|
Hello Mr. Cook.
I like your article ! Do you have any knowledge on designing RNG algorithms ? I mean all the math theory etc... If you do I would like to see some theory, in this or in another article. Perhaps this site isn't the best place to write articles for math but I think some programmers interested in math may find this usefull.
Thanks.
kostas KEL
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
For an introduction to the mathematical theory, you might want to start with volume 2 of Donald Knuth's Art of Computer Programming, Seminumerical Algorithms. Also, you may be interested in another CodeProject article I wrote, "[^]Pitfalls in Random Number Generation
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
you can just do this :
Random ran = new Random(); double d = ran.NextDouble();
and u will get a double between 0 and 1 then u can do what ever u want with it so why spnd time trying to create one ?
|
| Sign In·View Thread·PermaLink | 1.33/5 (3 votes) |
|
|
|
 |
|
|
For the fun maybe? Beside that, it's probably better to turn to System.Security.Cryptography for production code.
|
| Sign In·View Thread·PermaLink | 3.33/5 (2 votes) |
|
|
|
 |
|
|
 |
|
|
One reason for a custom generator is transparency. If you're trying to reproduce a problem and stepping through the code with a debugger, everything is right there in your code under your control.
Sometimes it's helpful to compare results of code written in different environments. If they all use their own library's RNG, the results aren't comparable. But, for example, you could use this code from unmanaged C++ and from C# and produce identical sequences if you start from identical seeds.
modified on Friday, April 11, 2008 10:08 PM
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
For one reason, the bug that was recently discovered in the random number generator used by Vista and everything that came before.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'll stick with what's built-in.
This is one of many areas where I know Microsoft can do better than I can.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
PIEBALDconsult wrote: This is one of many areas where I know Microsoft can do better than I can
This may be true, but others can do significantly better. You probably don't need really random numbers, but if you do, the in-built functions like rand() are not up to the task.
Peter "Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
That's fine for crypto work, but what about for statistical simulations (Monte Carlo etc), here you need very fast random number generation with good statistical properties. The inbuilt Random() function looks similar to rand() from c. I haven't made any serious use of random numbers in .NET, but it is possible that this simple generator could be useful.
Peter "Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This PRNG is only usable for monte carlo simulations. And i think it is better than rand() for this purpose, because it passes the DIEHARD tests, the build in rand() function don't!
Where are the problems in crypthography? 1. It is only 32Bit wide - no problem for a brute force attack, at least you need 128Bit, 160Bit or 256Bit is better. 2. It is guessable. If you have a number, you can guess the previous number because the algorithm has not the strength of an cryptography hash function like SHA or even MD5. If the output must be salted and hashed to masquerade, it looses it statistical distribution because of the hash function. In this case you can use a salted hash function to produce a PRN sequence like this:
salt = something real random number = 0; // Dosn't matter because of the salt! number = CryptoHash( number xor salt ) number = CryptoHash( number xor salt ) (replace CryptoHash with your prefered hash function like SHA)
Due to the fact that cryptographical hash functions are slow and often don't produce a perfect statistical distribution, it is not very good to use them for monte carlo simulations.
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
|
There are dozens of RNG's around. Each RNG is suitable for some situations but not in others. The two big classes are simulations and cryptography, and they are nearly mutually exclusive.
Crypto RNG's have a specific purpose: to show randomness that is not predictable from previous values. For example, given enough data points, it is possible to predict the next number in a Mersenne Twister sequence. So, even though its randomness is great, its predictibility makes it a no-no for cryptography applications.
Conversely, crypto RNG's tend to be slow, and may show some correlations that would be unacceptable in a simulation.
The built-in .NET RNG is decent, and will do for most people's uses. It is based on Knuth's 3rd RNG algorithm from The Art of Computer Programming, Vol.2. But for serious simulations, it is not adequate.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I think there are 2 reasons for building your own RNG:
1. As the author said :"The statistical (and not only) quality of the built-in generator might not be adequate for some tasks.". I.e.: cyptography. If someone knows the starting point (seed) of your RNG can figure out all the sequence, no matter how long that may be ! But if the algorithm is not a "common" or "well known" algorithm, then he has no chance finding anything!
2. That way you can balance, yourself, statistical quality and complexity (time delay) the way you want.
However, most apps don't need all this effort. And as you say MS usually does things work great! But don't underestimate this article !
Of course, I always prefer creating random numbers using natural, non-mathematical processes (some people even use radioactive sources to build RNG! - Yes that is a crazy world, isn't it?) but there is always an easier way!
kostas KEL
modified on Monday, August 25, 2008 11:48 AM
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
KEL3 wrote: But if the algorithm is not a "common" or "well known" algorithm
Security through obscurity?
KEL3 wrote: can figure out all the sequence
Yes, but you shouldn't use all the sequence. I always skip a few on each call so "they" would also need to know when each call was made.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
PIEBALDconsult wrote: "Security through obscurity?"
Well, that's the way I like to do things! Perhaps it's the best way too, when it's applicable. I mean, I 'm not a professional cryptographer, but if I ever need to encrypt sth, the less others know about my encryption method, the more I 'll be happy...! While professional cryptographers try to find the best "open to public" algorithm that would be unbreakable without the key, and when they think they did they fail to prove it mathematically, I would try to do things in the good old-fashioned way! Maybe that won't work for commercial applications but it works great for me!
PIEBALDconsult wrote: "Yes, but you shouldn't use all the sequence. I always skip a few on each call so "they" would also need to know when each call was made."
That's a nice idea! I just tend to make things the hardest possible and that's not good enough for my peculiar character! 
But even if you don't share my thoughts about all these (don't worry, that happens all the time with me) there is the second argument (for creating your own RNG) I mentioned, which is the most persuading. There are also the arguments of the author.
Well, if this work is needed and it won't take you so long to complete, why not give it a try... The more a person does, the more knowledge he gains!
kostas KEL
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
If you set a seed from a system time you risk having no random numbers but a set of predefined numbers.
Online poker sites had this problem initially because they used to seed their card shuffling algorithm with a system time based seed which was exploited. Players would reset their clock and "know" the locations of all the cards in the deck.
I am not an expert in Random Number Theory, just thought I would point it out.
Robert Kozak www.nowcom.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This doesn't matter if yo do some monte carlo simulations. For cyryptography you need a good seed with enough entropy. Microsoft clamis to use some operating system internal counters (performance data, running apps, mouse, keyboard, different oscillator frequencies and network card mac) to produce a seed for the crypto api RNG. Probably you can salt this with your own entropy (app start, mouse movement whatever), but i think it is enough for joe average cryptography.
In high security environments (eg. certification authority) you probably need a real random number device. Even devices based on radiocative decay don't pass all DIEHARD tests (George Marsaglia).
BTW: Poker websites are cryptography and monte carlo simulations togeher. They need to be secure and real random.
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|