Random in the wild
tedunangst.com
tedunangst.com
/* Generate a random number 0...5 inclusive */
int r = random() % 6;
The problem is that this results in a bias towards certain values, because the random() return space is probably not a whole multiple of the number you are modding. It's easier if you think what would happen if RAND_MAX were "10". Then the results 0,1,2,3,4 each have two opportunities of being selected for r, but "5" only has one. So 5 is half as likely as any other number. Terrible!Using float/double random()'s don't always help either, because floating point multiplication has non-uniform errors. Instead, what you really need is:
int random_n(int top) {
if (top <= 0) {
return -1;
}
while(1) {
int r = random(top);
if (r < (RAND_MAX - (RAND_MAX % top))) {
return r;
}
}
return -1;
}
Although it's better to replace random() itself with something that uses real entropy.Subtleties like this are hard to detect on code review, and even in testing ... the real lesson may be that the very interface behind random(void) is just broken. It really should be random(int) and take care of all of this for you, as many other languages/libraries do.
*[1] en.cppreference.com/w/cpp/numeric
http://en.cppreference.com/w/cpp/numeric/random/random_devic...
(GNU libstdc++ will use rdrand if possible, otherwise it will read from /dev/urandom: https://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libstdc%2B...)
[1] http://msdn.microsoft.com/en-us/library/bb982250.aspx
[2] https://github.com/llvm-mirror/libcxx/blob/master/src/random...
I'm also not sure what "hardware" has to do with that guarantee.
One example I can think of where a standard library got this right is Golang:
The Boost random library actually does the right thing, and states that boost::random_device must not be implemented where a proper source of random bits is not available. The standard tries to be all things to all people, and std::random_device ends up being useless for any serious application.
As a mathematical random number generation library, the C++ library is much superior to its Go counterpart, math/rand.
The two are not necessarily incompatible. The distributions in the C++ standard library are not married to the standard engines. You can quite straightforwardly write an engine that uses urandom internally and which is compatible with the standard distributions; see the last couple dozen lines of libc++'s random.cpp.
Now, whether there are instances where using a statistical adapter with cryptographically secure random numbers is appropriate is another question, and one which I am not qualified to answer. However, such adapters as std::uniform_int_distribution and std::independent_bits_engine, if it can be verified that they are implemented correctly (and that is admittedly a big "if"), would probably still be useful.
That said, if you want to figure it out, he did say they were "selected examples" from this list of projects: http://marc.info/?l=openbsd-tech&m=141776286105814&w=2 Also, you may be able to google for exact text matches with the code. (You might find other projects that have the exact same problem--but that is likely good enough.)
Good article
"The one operation that was not observed was substracting the pid from the time. More research into this subject is warranted."
It's actually simple (even if still not effective on pid wraparound) - pid numbers grow, at a rate of at least 1 per program execution. Time grows at around 1 second per second. If you substituted pid from time, there's a good chance you would get the same seed by running the app twice in a row.
So it's added instead, so that it always grows. And we pretend the wraparound happens very rarely.
Broken behaviour? Sure. Practical solution that works for 99% cases where non-critical randomness is required? Definitely.
Just use urandom. Or getentropy() if your OS supports it.
If you're not using it for cryptographic purposes, then I don't see why it matters. :)
If you need high quality randomness, you probably should use urandom. If no where else, when the program is first executed.
And if you're on Windows: https://github.com/php/php-src/blob/e6ea376a91514c59d21f4b53...
A Monte Carlo simulation absolutely needs to be able to produce the same numbers every time if you want to have a hope of debugging it. In a release version, yes, sure. But even there, people will still have concerns about replicating other people's results, so being careful with random seeds is important.
There was a program I was using that used libtommath, and used that library's mp_rand function. libtommath's mp_rand does various trickery but essentially adds two results of rand() together[0].
If you call rand() multiple times on OpenBSD you will get a sequence that alternates between odd and even, which is completely standards compliant. Because of this the result of adding two rand() results together will always be odd (odd + even = odd).
The program didn't need cryptographic levels of randomness, but only returning odd numbers turned out to be a bit of a problem.
[0] https://github.com/libtom/libtommath/blob/develop/bn_mp_rand...
As far as I know, Lua does not include Mersenne Twister. math.random() is just C rand().
CMRES is quite impressive, I get ~1500 MB/s out of it. Quite useful for generating large unique files for various testcases.
LuaJIT bundles its own Tausworthe PRNG [1].
————
0. http://www.lua.org/manual/5.2/manual.html#pdf-math.random
The dice seems biased to certain numbers, and the spreadsheet has the same items come up more than mundane statistics would otherwise suggest. (A 1/50 roll landing on the same item 2-3 times in a row, multiple times per day?)
It's gotten to the point where my users don't want to use my bot for RPGs. I'll have to see if using SecureRandom#random_number produces any different results