But these seem pretty old criticisms of the rand function
This may be a nitpick, but I want to point out what I think is a flaw in this logic. Compilers are often extremely conservative about changing program behaviour, even when that behaviour (foolishly) depends on implementation details.
This may or may not be true for the big compilers you’re familiar with, but it is conceivable that a compiler would keep a broken legacy RNG for compatibility reasons.
The following program on my macbook:
#include <cstdlib>
#include <iostream>
using namespace std;
int main() {
srand(1);
for (int i = 0; i < 20; ++i) {
cout << (i > 0 ? ", " : "") << rand();
}
cout << endl;
return 0;
}
produces the output
16807, 282475249, 1622650073, 984943658, 1144108930, 470211272, 101027544, 1457850878, 1458777923, 2007237709, 823564440, 1115438165, 1784484492, 74243042, 114807987, 1137522503, 1441282327, 16531729, 823378840, 143542612
which you can look up in OEIS: https://oeis.org/A096550, it is the sequence $$16807^n\bmod(2^{31}-1).$$
How this does under the SmallCrush RNG test (in the TestU01 library):
========= Summary results of SmallCrush =========
Version: TestU01 1.2.3
Generator: ulcg_CreateLCG
Number of statistics: 15
Total CPU time: 00:00:08.05
The following tests gave p-values outside [0.001, 0.9990]:
(eps means a value < 1.0e-300):
(eps1 means a value < 1.0e-15):
Test p-value
----------------------------------------------
1 BirthdaySpacings eps
2 Collision eps
6 MaxOft eps
----------------------------------------------
All other tests were passed
As far as I know there is simply no good reason to assume that rand()
might be okay. If you assume otherwise, you'll usually end up writing some extremely non-portable code that will break under different compilers on different systems.