Zaimplementuj generator liczb pseudolosowych korzystając z algorytmu Wichmann–Hill. Zmodyfikuj generator tak, aby zwracał liczby: z zakresu z częstosliwością:

• 1-10 -> 25%
• 11-50 -> 15%
• 51-75 -> 35%
• 76 - 99 -> 20%
• 100 -> 5%

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]))

``````