Skip to content

Commit 103fba3

Browse files
committed
feat: add decorator for checking the uniformity of the generator distribution
1 parent 2a1fcd2 commit 103fba3

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

pycustomrand/diagnostics.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from collections import defaultdict
2+
from functools import wraps
3+
from time import time
4+
5+
6+
def check_distribution(count: int = 1000, buckets: int = 10):
7+
"""
8+
Декоратор для проверки равномерности распределения генератора.
9+
10+
count - сколько раз запустить генератор.
11+
buckets - на сколько частей разбить диапазон [0, 1).
12+
"""
13+
def decorator(func):
14+
@wraps(func)
15+
def wrapper(*args, **kwargs):
16+
print(f"===== Запуск анализа распределения ({count} итераций) =====")
17+
start_time = time()
18+
previous_time = start_time
19+
20+
# Словарь для подсчета попаданий
21+
stats = defaultdict(int)
22+
23+
for i in range(count):
24+
# Каждые 5 секунд вывод текущей итерации
25+
current_time = time()
26+
if current_time - previous_time > 5:
27+
print(f"Нынешняя итерация: {i}")
28+
previous_time = current_time
29+
30+
val = func(*args, **kwargs)
31+
# Превращение числа 0.0-1.0 в номер корзины (0, 1, ..., buckets-1)
32+
# int() для корзин равного размера
33+
bucket_index = int(val * buckets)
34+
35+
# Защита от граничного случая, если выпадет ровно 1.0
36+
if bucket_index == buckets:
37+
bucket_index -= 1
38+
39+
stats[bucket_index] += 1
40+
41+
elapsed = time() - start_time
42+
print(f"Генерация завершена за {elapsed:.4f} сек.\n")
43+
44+
# Анализ результатов
45+
expected_percent = 100 / buckets
46+
print(f"{'Корзина':<10} | {'Кол-во':<10} | {'%':<10} | {'Отклонение':<10}")
47+
print("=" * 50)
48+
49+
max_diff = 0
50+
51+
for k in sorted(stats.keys()):
52+
v = stats[k]
53+
percent = (v / count) * 100
54+
diff = abs(percent - expected_percent)
55+
if diff > max_diff:
56+
max_diff = diff
57+
58+
print(f"{k:<10} | {v:<10} | {percent:<10.2f}% | {diff:<10.2f}%")
59+
60+
print("=" * 50)
61+
print(f"Максимальное отклонение: {max_diff:.4f}%")
62+
if max_diff < 1.0:
63+
print(">> РЕЗУЛЬТАТ: Отличное равномерное распределение!")
64+
else:
65+
print(">> РЕЗУЛЬТАТ: Есть перекосы (вероятно, мала выборка или проблема в алгоритме).")
66+
67+
# Возврат последнего сгенерированного числа, чтобы не ломать логику программы
68+
return val
69+
70+
return wrapper
71+
return decorator

0 commit comments

Comments
 (0)