
the latest xkcd on my internet is about a programming language that attempts to eliminate off-by-one errors via "every time an integer is stored or read, its value is adjusted up or down by a random amount between 40 and 50". The title text clarifies that this generates off-by-40-or-50 errors instead.
I'm looking a little into engaging cpython with a goal of implementing something like this. It's maybe not the best choice -- the interpreter is only used for one language, the language has other interpreters written for it, and i haven't yet found a single unified place to engage integer stores and loads -- but it's a language that I've been engaging recently, and recently spammed around engaging the bytecode of, which seems quite rare for me. it's 0613 ET. i'm looking for mentions of 'random' in the cpython source to figure out how to generate a random number :s random.py -> imports _random and from os imports urandom os.py -> imports * from posix or nt depending on platform Modules/_randommodule.c -> contains this line: #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() Here are some interesting floating point constants: static PyObject * _random_Random_random_impl(RandomObject *self) /*[clinic end generated code: output=117ff99ee53d755c input=26492e52d26e8b7b]*/ { uint32_t a=genrand_uint32(self)>>5, b=genrand_uint32(self)>>6; return PyFloat_FromDouble((a*67108864.0+b)*(1.0/9007199254740992.0)); } how much is one 9.007 quadrillionth? something to do with doubles or floats, 67.1 million, and 27 and 26 bit integers! i guess the 67.1 million would be to generate a higher bit integer, and the 9.007 quadrillion would be to scale it within 0 and 1. funny at first to see large integer constants in a floating point division context but makes sense. blurp arright ummm genrand_uint32 is a manual inline implementation and operates on a RandomObject :/ comments say that it's MT19937 hiroshima-u.ac.jp . 9.007 quadrillion is pow(2, 53). the python comments say "likely vain hope" regarding performing multiply-by-reciprocal rather than divide. the authors of the comments were maybe unaware that this optimization could double your frame rate in the 80s and 90s, and spreading of newer such optimizations dropped after hardware advanced. 67.1 million is pow(2,26). current options: - initializing and using random state using this compiled mt19937 module - using code from nt or posix module to compute random - including my own random header or such - placing a manual implementation of a generation algorithm i'm visiting Modules/posixmodule.c it's notable that these functions have comments along the lines of "clinic end generated code" ... but i'm guessing it's the signatures that are generated, not the bodies os_urandom_impl in posixmodule.c hands off to _PyOS_URandom it looks like posixmodule.c defines both the "posix" and the "nt" modules conditioned on platform looks like both _PyOS_URandom _PyOS_URandomNonblock are pulled in from pycore_pylifecycle.h the definitions though are in Python/bootstrap_hash.c . it defines a few different random number generators, strange to see this after the inline generator from the japanese university code. usually these two things would be unified together. notably these random number generators i'm not seeing them in the header file yet win32_urandom -> calls BCryptGenRandom, a windows call py_getrandom -> calls getrandom(), a linux kernel syscall py_getentropy -> calls getentropy() dev_urandom -> reads /dev/urandom lcg_urandom -> manual linear congruential generator pyurandom -> hands off to the first 4 above in order if available, does not use lcg_urandom _PyOS_URandom* -> hand off to pyurandom so to generate a number between 40 and 50 i suppose i'd call a _PyOS_URandom function and read 1 byte. i could keep a bit cache if i were fancy, but would likely make more sense to spend time on ensuring integer stores and loads are properly effected.