# Ranlux 24/48 PRNGs. (1.01)
# Chaotic with long period but slow (due to discard).

from collections import deque
from random import choices

class SubtractWithCarryEngine:
    def __init__(self, w, s, r):
        assert 0 < w
        assert 0 < s < r
        self.m = 2**w-1
        self.s = s
        self.r = r
        self.x = deque(choices(range(2**w), k=r), maxlen=r)
        self.c = 0

    def next(self):
        x = self.x
        i = len(x)
        y = x[i - self.s] - x[i - self.r] - self.c
        self.c = 1 if y < 0 else 0
        x.append(y & self.m)
        return x[-1]

    def discard(self, n):
        for _ in range(n):
            self.next()

class DiscardBlockEngine:
    def __init__(self, g, p, r):
        assert 0 < r <= p
        self.g = g
        self.p = p
        self.r = r
        self.n = r

    def next(self):
        if self.n == 0:
            self.g.discard(self.p - self.r)
            self.n = self.r
        self.n -= 1
        return self.g.next()

# Test.

def bitstream(n, prng, bits, *, end='\n', file=None):
    assert bits > 0
    while n > 0:
        m = min(n, bits)
        n -= m
        r = prng.next()
        for i in reversed(range(bits - m, bits)):
            print(chr(((r >> i) & 1) + ord('0')), end='', file=file)
    print(end=end, file=file)

ranlux24_base = SubtractWithCarryEngine(24, 10, 24)
ranlux24 = DiscardBlockEngine(ranlux24_base, 223, 23)
ranlux48_base = SubtractWithCarryEngine(48, 5, 12)
ranlux48 = DiscardBlockEngine(ranlux48_base, 389, 11)

n = 50
bitstream(n, ranlux24, 24)
bitstream(n, ranlux48, 48)

print('Ranlux24:')
for i in range(24):
    print(' ', ranlux24.next())
print('Ranlux48:')
for i in range(12):
    print(' ', ranlux48.next())