-
Notifications
You must be signed in to change notification settings - Fork 2k
[aiohttp] - use lcg as random generator #9942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from random import randint | ||
|
||
# Constants | ||
# https://statmath.wu.ac.at/software/src/prng-3.0.2/doc/prng.html/Table_LCG.html | ||
MAX_VALUE = 10000 | ||
MODULOS = 134217689 | ||
LCG_MULTIPLIER = 3162696 | ||
RANDOM_THRESHOLD = MODULOS - (MODULOS % (MAX_VALUE)) | ||
|
||
seed = randint(0, MAX_VALUE) | ||
|
||
def random_id(): | ||
"""Generate a pseudo-random number based on a linear congruential generator""" | ||
global seed | ||
|
||
# Regenerate if we're above the threshold to avoid distribution bias | ||
while True: | ||
seed = (LCG_MULTIPLIER * seed) % MODULOS | ||
if seed < RANDOM_THRESHOLD: | ||
break | ||
|
||
return 1 + seed % MAX_VALUE | ||
|
||
def random_unique_ids(n): | ||
"""Generate n unique random IDs""" | ||
generated_ids = {random_id() for _ in range(n)} | ||
|
||
while len(generated_ids) < n: | ||
id_ = random_id() | ||
if id_ not in generated_ids: | ||
generated_ids.add(id_) | ||
|
||
return list(generated_ids) |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This kind of feels like cheating, this seems beyond benchmarking a realistic framework. This feels more like a potential contribution to cpython to provide faster built-in random functions, thus benefiting everyone. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Agreed, but like many other things, module-level caching, execute queries without read actual results.
This is certainly not intended as a contribution to Python itself, since LCGs are inferior to existing random number generators. They have significantly shorter periods, and their speed advantage comes only from the small space size and the simplicity of the algorithm. In our case, the short period and predictability of the sequence don’t matter—we’re not aiming for cryptographic or truly random values—but overall, LCGs are still a poor choice. We are going back to the roots here 😀 Even Python 1.0 had improved version of LCG |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# cython: boundscheck=False | ||
# cython: wraparound=False | ||
# cython: initializedcheck=False | ||
# cython: cdivision=True | ||
|
||
from libc.stdlib cimport calloc, free | ||
|
||
import random | ||
|
||
# Constants | ||
cdef const unsigned short MAX_VALUE = 10000 | ||
# https://statmath.wu.ac.at/software/src/prng-3.0.2/doc/prng.html/Table_LCG.html | ||
cdef const unsigned int MODULOS = 134217689 | ||
cdef const unsigned long LCG_MULTIPLIER = 3162696 | ||
|
||
cdef unsigned int RANDOM_THRESHOLD = MODULOS - (MODULOS % MAX_VALUE) | ||
cdef char* seen = <char*>calloc(MAX_VALUE + 1, sizeof(char)) # Bit array simulation | ||
|
||
cdef unsigned int seed = random.randint(1, MODULOS-1) | ||
|
||
cdef inline unsigned int _next_random() noexcept nogil: | ||
"""Generate a pseudo-random number based on a linear congruential generator""" | ||
global seed | ||
|
||
cdef unsigned int next_val = (LCG_MULTIPLIER * seed) % MODULOS | ||
|
||
while next_val >= RANDOM_THRESHOLD: | ||
next_val = (LCG_MULTIPLIER * next_val) % MODULOS | ||
|
||
seed = next_val | ||
return seed | ||
|
||
cpdef unsigned short random_id() noexcept nogil: | ||
"""Generate a pseudo-random number in range [1, MAX_VALUE]""" | ||
return 1 + (_next_random() % MAX_VALUE) | ||
|
||
cpdef list[unsigned short] random_unique_ids(unsigned short n): | ||
"""Generate n unique random IDs in range[1, 10001]""" | ||
cdef list[unsigned short] result = [0] * n | ||
cdef unsigned short candidate, count = 0 | ||
|
||
try: | ||
while count < n: | ||
candidate = 1 + (_next_random() % MAX_VALUE) | ||
|
||
if seen[candidate] == 0: # Not seen before | ||
seen[candidate] = 1 | ||
result[count] = candidate | ||
count += 1 | ||
finally: | ||
for i in result: | ||
seen[i] = 0 | ||
|
||
return result | ||
|
||
def _cleanup(): | ||
global seen | ||
if seen != NULL: | ||
free(seen) | ||
seen = NULL | ||
|
||
import atexit | ||
atexit.register(_cleanup) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from setuptools import setup, Extension | ||
from Cython.Build import cythonize | ||
|
||
setup( | ||
ext_modules=cythonize([ | ||
Extension( | ||
"app.random_utils", | ||
["app/random_utils.pyx"], | ||
extra_compile_args=["-O3"] | ||
), | ||
]) | ||
) |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do use this, we atleast want dependencies in the requirements files, so they can be updated with Dependabot.