We compare three widely used random-number interfaces, Python’s random (Mersenne Twister, MT19937), NumPy’s PCG64, and Python’s secrets (the operating-system CSPRNG), using five classical diagnostics on outputs in {0,...,9}: a chi-square frequency test, lag-1 correlation, Good’s serial tests on overlapping pairs and triples, and a Wald-Wolfowitz runs test, with two known-weak generators as positive controls. In a fixed-seed primary run (N = 10^6) and in 300 independent replications per generator, none of the three generators shows a detectable departure from the null model after Holm correction, and the replicated p-values are consistent with a uniform distribution. A low runs-test p-value (p = 0.0023) observed for secrets in an initial execution did not recur (1 of 300 replications reached that level) and is best explained as chance. The positive controls show that these diagnostics have real but narrow power: a low-digit LCG fails almost every test, whereas RANDU passes every test except serial triples. The same diagnostics are blind to the structure of MT19937: Berlekamp-Massey analysis of a single output bit gives a linear complexity of exactly 19,937 (versus about 25,000 for PCG64 and the OS CSPRNG over 50,000 bits), and 624 observed 32-bit outputs suffice to predict all subsequent outputs, including randrange(10) values, with 100% accuracy. Passing statistical tests therefore neither certifies randomness nor implies unpredictability. All results are reproducible with the accompanying code.
No takes yet. Share an insight, caveat, or question.
Mihaita Hingan (2026) studied this question.
Synapse has enriched 5 closely related papers on similar clinical questions. Consider them for comparative context: