diff -r 451559508c54 Lib/random.py --- a/Lib/random.py Mon Dec 10 16:35:16 2012 +0100 +++ b/Lib/random.py Tue Dec 11 00:14:26 2012 +0200 @@ -43,6 +43,7 @@ from os import urandom as _urandom from collections.abc import Set as _Set, Sequence as _Sequence from hashlib import sha512 as _sha512 +from struct import pack as _pack, unpack as _unpack __all__ = ["Random","seed","random","uniform","randint","choice","sample", "randrange","shuffle","normalvariate","lognormvariate", @@ -59,13 +60,144 @@ RECIP_BPF = 2**-BPF +# Period parameters -- These are all magic. Don't change. +_N = 624 +_M = 397 + +class _Random: + def __new__(cls, *args, **kwargs): + if cls == _Random and kwargs: + raise TypeError('Random() does not take keyword arguments') + self = super(_Random, cls).__new__(cls) + self.seed(*args) + return self + + def random(self): + """random() -> x in the interval [0, 1).""" + a = self._genrand_int32() >> 5 + b = self._genrand_int32() >> 6 + return (a * 67108864 + b) * (1 / 9007199254740992) + + def seed(self, n=None): + """seed([n]) -> None. Defaults to current time.""" + if n is None: + self._init_genrand(int(time.time())) + return None + if isinstance(n, int): + n = abs(n) + else: + n = hash(n) + if n < 0: + n, = _unpack('N', _pack('n', n)) + # Now split n into 32-bit chunks, from the right. + bits = n.bit_length() + keysize = (bits - 1) // 32 + 1 if bits else 1 + key = _unpack('<%dI' % keysize, n.to_bytes(keysize * 4, 'little')) + self._init_by_array(key) + + def getstate(self): + """getstate() -> tuple containing the current state.""" + return tuple(self.state) + (self.index,) + + def setstate(self, state): + """setstate(state) -> None. Restores generator state.""" + if not isinstance(state, tuple): + raise TypeError('state vector must be a tuple') + if len(state) != _N + 1: + raise ValueError('state vector is the wrong size') + self.state = [x & 0xffffffff for x in state[:-1]] + self.index = int(state[-1]) + + def getrandbits(self, k): + """getrandbits(k) -> x. Generates a long int with k random bits.""" + if k <= 0: + raise ValueError('number of bits must be greater than zero') + + # Fill-out whole words, byte-by-byte to avoid endianness issues + words = [self._genrand_int32() for i in range((k - 1) // 32 + 1)] + k %= 32 + if k: + words[-1] = words[-1] >> (32 - k) + # little endian order to match bytearray assignment order + return int.from_bytes(_pack('<%dI' % len(words), *words), 'little') + + # generates a random number on [0,0xffffffff]-interval + def _genrand_int32(self, N=_N, M=_M): + mt = self.state + try: + y = mt[self.index] + self.index += 1 + except IndexError: + # generate N words at one time + for kk in range(N): + y = (mt[kk] & 0x80000000) | (mt[kk + 1 - N] & 0x7fffffff) + x = mt[kk + M - N] ^ (y >> 1) + if y & 1: + x ^= 0x9908b0df + mt[kk] = x + y = mt[0] + self.index = 1 + + y ^= (y >> 11) + y ^= (y << 7) & 0x9d2c5680 + y ^= (y << 15) & 0xefc60000 + y ^= (y >> 18) + return y + + # initializes mt[N] with a seed + def _init_genrand(self, s, N=_N): + x = s & 0xffffffff + mt = [x] + append = mt.append + for i in range(1, N): + x = (1812433253 * (x ^ (x >> 30)) + i) & 0xffffffff + append(x) + # See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. + # In the previous versions, MSBs of the seed affect + # only MSBs of the array mt[]. + # 2002/01/09 modified by Makoto Matsumoto + self.state = mt + self.index = N + + # initialize by an array with array-length + # init_key is the array for initializing keys + # key_length is its length + def _init_by_array(self, init_key, N=_N): + self._init_genrand(19650218) + mt = self.state + i = 1 + j = 0 + x = mt[0] + for k in range(max(N, len(init_key))): + mt[i] = x = ((mt[i] ^ ((x ^ (x >> 30)) * 1664525)) + + init_key[j] + j) & 0xffffffff + i += 1 + if i >= N: + mt[0] = x + i = 1 + j += 1 + if j >= len(init_key): + j = 0 + for k in range(N - 1): + mt[i] = x = ((mt[i] ^ ((x ^ (x >> 30)) * 1566083941)) - + i) & 0xffffffff + i += 1 + if i >= N: + mt[0] = x + i = 1 + mt[0] = 0x80000000 # MSB is 1; assuring non-zero initial array + +try: + from _random import Random as _Random +except ImportError: + pass + + # Translated by Guido van Rossum from C source provided by # Adrian Baddeley. Adapted by Raymond Hettinger for use with # the Mersenne Twister and os.urandom() core generators. -import _random - -class Random(_random.Random): +class Random(_Random): """Random number generator base class used by bound module functions. Used to instantiate instances of Random to get generators that don't