Zaimplementuj generator liczb pseudolosowych korzystając z algorytmu Wichmann–Hill. Zmodyfikuj generator tak, aby zwracał liczby: z zakresu z częstosliwością:
Na próbce 100 tysięcy liczb, oblicz rozkład.
function(s1, s2, s3)
s1 = mod (
171 * s1
, 30269 )s2 = mod (
172 * s2
, 30307 )s3 = mod (
170 * s3
, 30323 )r = mod ( s1/30269 + s2/30307 + s3/30323, 1 )
return r
In [ ]:
import time
from functools import partial
from collections import Counter
class RandomNumbersGenerator():
def __init__(self):
self.s1 = time.time()
self.s2 = time.time()
self.s3 = time.time()
def _linear_rng(self):
while True:
self.s1 = (171 * self.s1) % 30269
self.s2 = (172 * self.s2) % 30307
self.s3 = (170 * self.s3) % 30323
yield (self.s1 / 30269.0 + self.s2 / 30307.0 + self.s3 / 30323.0) % 1.0
def __iter__(self):
rng = self._linear_rng()
inrange = lambda min, max: int(next(rng) * abs(max - min) + min)
while True:
rn = next(rng)
if rn <= 0.25:
yield inrange(1, 10)
elif 0.25 < rn <= 0.4:
yield inrange(11, 50)
elif 0.4 < rn <= 0.75:
yield inrange(51, 75)
elif 0.75 < rn <= 0.95:
yield inrange(76, 99)
else:
yield 100
def __enter__(self):
return iter(self)
def __exit__(self, *args):
pass
In [ ]:
AMOUNT = 100000
with RandomNumbersGenerator() as rng:
rng_gen = partial(next, rng)
ct = Counter()
for i in range(AMOUNT):
rn = rng_gen()
if rn in range(1, 11):
ct[(1, 10)] += 1
elif rn in range(11, 51):
ct[(11, 50)] += 1
elif rn in range(51, 76):
ct[(51, 75)] += 1
elif rn in range(76, 100):
ct[(76, 99)] += 1
else:
ct[(100,)] += 1
print(sorted(ct.items(), key=lambda x: x[0]))