import itertools as IT
import random
from collections import Counter
MOD = 2**31
def rint(m):
return random.randrange(0, m)
def ansic(seed=None):
M = 2**31
if seed is None:
seed = rint(0, M)
while True:
seed = (seed * 1103515245 + 12345) % M
yield seed >> 16
def randu(seed=None):
if seed is None:
seed = rint(MOD)
while True:
seed = (seed * 65539) % MOD
yield seed
def park_miller(seed=None):
if seed is None:
seed = rint(MOD)
while True:
seed = (seed * 16807) % (MOD-1)
yield seed
def java(seed=None):
F = 2**48
if seed is None:
seed = rint(F)
while True:
seed = (seed * 25214903917 + 11) % (F-1)
yield seed >> 16
def prng_to_bits(rng, nbits):
while True:
b = bin(next(rng))[2:]
yield from (int(bi) for bi in reversed(b))
yield from IT.repeat(0, nbits - len(b))
def create_bits(rng, nbits, m):
def bits():
yield from prng_to_bits(rng(rint(m)), nbits)
bits.__name__ = rng.__name__ + "_bits"
return bits
park_miller_bits = create_bits(park_miller, 31, MOD)
randu_bits = create_bits(randu, 31, MOD)
ansic_bits = create_bits(ansic, 15, MOD)
java_bits = create_bits(java, 32, 2**48)
def python_bits():
while True:
yield random.getrandbits(1)
def count_bits(n):
return bin(n).count("1")
def ones_test(prng, n=200):
ones = sum(count_bits(next(prng)) for _ in range(n))
expected = n / 2
lo, hi = round(expected - 2 *stdev), round(expected + 2 * stdev)
if not lo < ones < hi:
# print("Ones not {} < {} < {} - {}".format(lo, ones, hi, prng.__name__))
return 0
return 1
def count_bit_runs(prng, n=1000):
return Counter(len(list(g)) for
k, g in IT.groupby(IT.islice(prng, n)) if k == 1)
def runs_test(prng, nbits=100000):
runs = count_bit_runs(prng, nbits)
longest_run = max(runs.keys())
eruns
, esdev
= -log(nbits
/2)/log(0.5), 1 / log(2) rlo
, rhi
= ceil(eruns
- 2 * esdev
), floor(eruns
+ 2 * esdev
) if not rlo <= longest_run <= rhi:
# print("Run not {} < {} < {} - {}".format(rlo, longest_run, rhi, prng.__name__))
return 0
return 1
def tests(prng, nbits=100000):
s1 = ones_test(prng, n=nbits)
s2 = runs_test(prng, nbits)
return s1 + s2
N = 10000
ncases = 50
for rng in (park_miller_bits, randu_bits, java_bits, python_bits, ansic_bits):
score = 0
for i in range(ncases):
score += tests(rng(), N)
print("{:16s} {}/{}".format(rng.__name__, score, 2*ncases))
ZnJvbSBtYXRoIGltcG9ydCBsb2csIGV4cCwgc3FydCwgZmxvb3IsIGNlaWwsIGxvZzIKaW1wb3J0IGl0ZXJ0b29scyBhcyBJVAppbXBvcnQgcmFuZG9tCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IENvdW50ZXIKCk1PRCA9IDIqKjMxCgpkZWYgcmludChtKToKICAgIHJldHVybiByYW5kb20ucmFuZHJhbmdlKDAsIG0pCgpkZWYgYW5zaWMoc2VlZD1Ob25lKToKICAgIE0gPSAyKiozMQogICAgaWYgc2VlZCBpcyBOb25lOgogICAgICAgIHNlZWQgPSByaW50KDAsIE0pCiAgICB3aGlsZSBUcnVlOgogICAgICAgIHNlZWQgPSAoc2VlZCAqIDExMDM1MTUyNDUgKyAxMjM0NSkgJSBNCiAgICAgICAgeWllbGQgc2VlZCA+PiAxNgoKZGVmIHJhbmR1KHNlZWQ9Tm9uZSk6CiAgICBpZiBzZWVkIGlzIE5vbmU6CiAgICAgICAgc2VlZCA9IHJpbnQoTU9EKQogICAgd2hpbGUgVHJ1ZToKICAgICAgICBzZWVkID0gKHNlZWQgKiA2NTUzOSkgJSBNT0QKICAgICAgICB5aWVsZCBzZWVkCgpkZWYgcGFya19taWxsZXIoc2VlZD1Ob25lKToKICAgIGlmIHNlZWQgaXMgTm9uZToKICAgICAgICBzZWVkID0gcmludChNT0QpCiAgICB3aGlsZSBUcnVlOgogICAgICAgIHNlZWQgPSAoc2VlZCAqIDE2ODA3KSAlIChNT0QtMSkKICAgICAgICB5aWVsZCBzZWVkCgpkZWYgamF2YShzZWVkPU5vbmUpOgogICAgRiA9IDIqKjQ4CiAgICBpZiBzZWVkIGlzIE5vbmU6CiAgICAgICAgc2VlZCA9IHJpbnQoRikKICAgIHdoaWxlIFRydWU6CiAgICAgICAgc2VlZCA9IChzZWVkICogMjUyMTQ5MDM5MTcgKyAxMSkgJSAoRi0xKQogICAgICAgIHlpZWxkIHNlZWQgPj4gMTYKCmRlZiBwcm5nX3RvX2JpdHMocm5nLCBuYml0cyk6CiAgICB3aGlsZSBUcnVlOgogICAgICAgIGIgPSBiaW4obmV4dChybmcpKVsyOl0KICAgICAgICB5aWVsZCBmcm9tIChpbnQoYmkpIGZvciBiaSBpbiByZXZlcnNlZChiKSkKICAgICAgICB5aWVsZCBmcm9tIElULnJlcGVhdCgwLCBuYml0cyAtIGxlbihiKSkKCmRlZiBjcmVhdGVfYml0cyhybmcsIG5iaXRzLCBtKToKICAgIGRlZiBiaXRzKCk6CiAgICAgICAgeWllbGQgZnJvbSBwcm5nX3RvX2JpdHMocm5nKHJpbnQobSkpLCBuYml0cykKICAgIGJpdHMuX19uYW1lX18gPSBybmcuX19uYW1lX18gKyAiX2JpdHMiCiAgICByZXR1cm4gYml0cwoKcGFya19taWxsZXJfYml0cyA9IGNyZWF0ZV9iaXRzKHBhcmtfbWlsbGVyLCAzMSwgTU9EKQpyYW5kdV9iaXRzID0gY3JlYXRlX2JpdHMocmFuZHUsIDMxLCBNT0QpCmFuc2ljX2JpdHMgPSBjcmVhdGVfYml0cyhhbnNpYywgMTUsIE1PRCkKamF2YV9iaXRzID0gY3JlYXRlX2JpdHMoamF2YSwgMzIsIDIqKjQ4KQoKZGVmIHB5dGhvbl9iaXRzKCk6CiAgICB3aGlsZSBUcnVlOgogICAgICAgIHlpZWxkIHJhbmRvbS5nZXRyYW5kYml0cygxKQoKZGVmIGNvdW50X2JpdHMobik6CiAgICByZXR1cm4gYmluKG4pLmNvdW50KCIxIikKCmRlZiBvbmVzX3Rlc3QocHJuZywgbj0yMDApOgogICAgb25lcyAgPSBzdW0oY291bnRfYml0cyhuZXh0KHBybmcpKSBmb3IgXyBpbiByYW5nZShuKSkKICAgIGV4cGVjdGVkID0gbiAvIDIKICAgIHN0ZGV2ID0gc3FydChuIC8gNCkKICAgIGxvLCBoaSA9IHJvdW5kKGV4cGVjdGVkIC0gMiAqc3RkZXYpLCByb3VuZChleHBlY3RlZCArIDIgKiBzdGRldikKICAgIGlmIG5vdCBsbyA8IG9uZXMgPCBoaToKICAgICAgICAjIHByaW50KCJPbmVzIG5vdCB7fSA8IHt9IDwge30gLSB7fSIuZm9ybWF0KGxvLCBvbmVzLCBoaSwgcHJuZy5fX25hbWVfXykpCiAgICAgICAgcmV0dXJuIDAKICAgIHJldHVybiAxCgpkZWYgY291bnRfYml0X3J1bnMocHJuZywgbj0xMDAwKToKICAgIHJldHVybiBDb3VudGVyKGxlbihsaXN0KGcpKSBmb3IKICAgICAgICAgICAgICAgICAgIGssIGcgaW4gSVQuZ3JvdXBieShJVC5pc2xpY2UocHJuZywgbikpIGlmIGsgPT0gMSkKCmRlZiBydW5zX3Rlc3QocHJuZywgbmJpdHM9MTAwMDAwKToKICAgIHJ1bnMgPSBjb3VudF9iaXRfcnVucyhwcm5nLCBuYml0cykKICAgIGxvbmdlc3RfcnVuID0gbWF4KHJ1bnMua2V5cygpKQogICAgZXJ1bnMsIGVzZGV2ID0gIC1sb2cobmJpdHMvMikvbG9nKDAuNSksIDEgLyBsb2coMikKICAgIHJsbywgcmhpID0gY2VpbChlcnVucyAtIDIgKiBlc2RldiksIGZsb29yKGVydW5zICsgMiAqIGVzZGV2KQogICAgaWYgbm90IHJsbyA8PSBsb25nZXN0X3J1biA8PSByaGk6CiAgICAgICAgIyBwcmludCgiUnVuIG5vdCB7fSA8IHt9IDwge30gLSB7fSIuZm9ybWF0KHJsbywgbG9uZ2VzdF9ydW4sIHJoaSwgcHJuZy5fX25hbWVfXykpCiAgICAgICAgcmV0dXJuIDAKICAgIHJldHVybiAxCgpkZWYgdGVzdHMocHJuZywgbmJpdHM9MTAwMDAwKToKICAgIHMxID0gb25lc190ZXN0KHBybmcsIG49bmJpdHMpCiAgICBzMiA9IHJ1bnNfdGVzdChwcm5nLCBuYml0cykKICAgIHJldHVybiBzMSArIHMyCgpOID0gMTAwMDAKbmNhc2VzID0gNTAKZm9yIHJuZyBpbiAocGFya19taWxsZXJfYml0cywgcmFuZHVfYml0cywgamF2YV9iaXRzLCBweXRob25fYml0cywgYW5zaWNfYml0cyk6CiAgICBzY29yZSA9IDAKICAgIGZvciBpIGluIHJhbmdlKG5jYXNlcyk6CiAgICAgICAgc2NvcmUgKz0gdGVzdHMocm5nKCksIE4pCiAgICBwcmludCgiezoxNnN9ICB7fS97fSIuZm9ybWF0KHJuZy5fX25hbWVfXywgc2NvcmUsIDIqbmNhc2VzKSkK