mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Remove defunct parts of the random module
This commit is contained in:
parent
f7ec7a81a5
commit
28de64fd0f
6 changed files with 32 additions and 360 deletions
|
@ -28,25 +28,14 @@ for cryptographic purposes.
|
||||||
|
|
||||||
The functions supplied by this module are actually bound methods of a hidden
|
The functions supplied by this module are actually bound methods of a hidden
|
||||||
instance of the :class:`random.Random` class. You can instantiate your own
|
instance of the :class:`random.Random` class. You can instantiate your own
|
||||||
instances of :class:`Random` to get generators that don't share state. This is
|
instances of :class:`Random` to get generators that don't share state.
|
||||||
especially useful for multi-threaded programs, creating a different instance of
|
|
||||||
:class:`Random` for each thread, and using the :meth:`jumpahead` method to make
|
|
||||||
it likely that the generated sequences seen by each thread don't overlap.
|
|
||||||
|
|
||||||
Class :class:`Random` can also be subclassed if you want to use a different
|
Class :class:`Random` can also be subclassed if you want to use a different
|
||||||
basic generator of your own devising: in that case, override the :meth:`random`,
|
basic generator of your own devising: in that case, override the :meth:`random`,
|
||||||
:meth:`seed`, :meth:`getstate`, :meth:`setstate` and :meth:`jumpahead` methods.
|
:meth:`seed`, :meth:`getstate`, and :meth:`setstate`.
|
||||||
Optionally, a new generator can supply a :meth:`getrandombits` method --- this
|
Optionally, a new generator can supply a :meth:`getrandombits` method --- this
|
||||||
allows :meth:`randrange` to produce selections over an arbitrarily large range.
|
allows :meth:`randrange` to produce selections over an arbitrarily large range.
|
||||||
|
|
||||||
As an example of subclassing, the :mod:`random` module provides the
|
|
||||||
:class:`WichmannHill` class that implements an alternative generator in pure
|
|
||||||
Python. The class provides a backward compatible way to reproduce results from
|
|
||||||
earlier versions of Python, which used the Wichmann-Hill algorithm as the core
|
|
||||||
generator. Note that this Wichmann-Hill generator can no longer be recommended:
|
|
||||||
its period is too short by contemporary standards, and the sequence generated is
|
|
||||||
known to fail some stringent randomness tests. See the references below for a
|
|
||||||
recent variant that repairs these flaws.
|
|
||||||
|
|
||||||
Bookkeeping functions:
|
Bookkeeping functions:
|
||||||
|
|
||||||
|
@ -79,17 +68,6 @@ Bookkeeping functions:
|
||||||
the time :func:`setstate` was called.
|
the time :func:`setstate` was called.
|
||||||
|
|
||||||
|
|
||||||
.. function:: jumpahead(n)
|
|
||||||
|
|
||||||
Change the internal state to one different from and likely far away from the
|
|
||||||
current state. *n* is a non-negative integer which is used to scramble the
|
|
||||||
current state vector. This is most useful in multi-threaded programs, in
|
|
||||||
conjuction with multiple instances of the :class:`Random` class:
|
|
||||||
:meth:`setstate` or :meth:`seed` can be used to force all instances into the
|
|
||||||
same internal state, and then :meth:`jumpahead` can be used to force the
|
|
||||||
instances' states far apart.
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: getrandbits(k)
|
.. function:: getrandbits(k)
|
||||||
|
|
||||||
Returns a python integer with *k* random bits. This method is supplied with
|
Returns a python integer with *k* random bits. This method is supplied with
|
||||||
|
@ -224,24 +202,6 @@ be found in any statistics text.
|
||||||
|
|
||||||
Alternative Generators:
|
Alternative Generators:
|
||||||
|
|
||||||
.. class:: WichmannHill([seed])
|
|
||||||
|
|
||||||
Class that implements the Wichmann-Hill algorithm as the core generator. Has all
|
|
||||||
of the same methods as :class:`Random` plus the :meth:`whseed` method described
|
|
||||||
below. Because this class is implemented in pure Python, it is not threadsafe
|
|
||||||
and may require locks between calls. The period of the generator is
|
|
||||||
6,953,607,871,644 which is small enough to require care that two independent
|
|
||||||
random sequences do not overlap.
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: whseed([x])
|
|
||||||
|
|
||||||
This is obsolete, supplied for bit-level compatibility with versions of Python
|
|
||||||
prior to 2.1. See :func:`seed` for details. :func:`whseed` does not guarantee
|
|
||||||
that distinct integer arguments yield distinct internal states, and can yield no
|
|
||||||
more than about 2\*\*24 distinct internal states in all.
|
|
||||||
|
|
||||||
|
|
||||||
.. class:: SystemRandom([seed])
|
.. class:: SystemRandom([seed])
|
||||||
|
|
||||||
Class that uses the :func:`os.urandom` function for generating random numbers
|
Class that uses the :func:`os.urandom` function for generating random numbers
|
||||||
|
@ -281,6 +241,4 @@ Examples of basic usage::
|
||||||
equidistributed uniform pseudorandom number generator", ACM Transactions on
|
equidistributed uniform pseudorandom number generator", ACM Transactions on
|
||||||
Modeling and Computer Simulation Vol. 8, No. 1, January pp.3-30 1998.
|
Modeling and Computer Simulation Vol. 8, No. 1, January pp.3-30 1998.
|
||||||
|
|
||||||
Wichmann, B. A. & Hill, I. D., "Algorithm AS 183: An efficient and portable
|
|
||||||
pseudo-random number generator", Applied Statistics 31 (1982) 188-190.
|
|
||||||
|
|
||||||
|
|
166
Lib/random.py
166
Lib/random.py
|
@ -30,9 +30,6 @@ General notes on the underlying Mersenne Twister core generator:
|
||||||
|
|
||||||
* The period is 2**19937-1.
|
* The period is 2**19937-1.
|
||||||
* It is one of the most extensively tested generators in existence.
|
* It is one of the most extensively tested generators in existence.
|
||||||
* Without a direct way to compute N steps forward, the semantics of
|
|
||||||
jumpahead(n) are weakened to simply jump to another distant state and rely
|
|
||||||
on the large period to avoid overlapping sequences.
|
|
||||||
* The random() method is implemented in C, executes in a single Python step,
|
* The random() method is implemented in C, executes in a single Python step,
|
||||||
and is, therefore, threadsafe.
|
and is, therefore, threadsafe.
|
||||||
|
|
||||||
|
@ -49,7 +46,7 @@ __all__ = ["Random","seed","random","uniform","randint","choice","sample",
|
||||||
"randrange","shuffle","normalvariate","lognormvariate",
|
"randrange","shuffle","normalvariate","lognormvariate",
|
||||||
"expovariate","vonmisesvariate","gammavariate",
|
"expovariate","vonmisesvariate","gammavariate",
|
||||||
"gauss","betavariate","paretovariate","weibullvariate",
|
"gauss","betavariate","paretovariate","weibullvariate",
|
||||||
"getstate","setstate","jumpahead", "WichmannHill", "getrandbits",
|
"getstate","setstate", "getrandbits",
|
||||||
"SystemRandom"]
|
"SystemRandom"]
|
||||||
|
|
||||||
NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)
|
NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)
|
||||||
|
@ -70,14 +67,11 @@ class Random(_random.Random):
|
||||||
"""Random number generator base class used by bound module functions.
|
"""Random number generator base class used by bound module functions.
|
||||||
|
|
||||||
Used to instantiate instances of Random to get generators that don't
|
Used to instantiate instances of Random to get generators that don't
|
||||||
share state. Especially useful for multi-threaded programs, creating
|
share state.
|
||||||
a different instance of Random for each thread, and using the jumpahead()
|
|
||||||
method to ensure that the generated sequences seen by each thread don't
|
|
||||||
overlap.
|
|
||||||
|
|
||||||
Class Random can also be subclassed if you want to use a different basic
|
Class Random can also be subclassed if you want to use a different basic
|
||||||
generator of your own devising: in that case, override the following
|
generator of your own devising: in that case, override the following
|
||||||
methods: random(), seed(), getstate(), setstate() and jumpahead().
|
methods: random(), seed(), getstate(), and setstate().
|
||||||
Optionally, implement a getrandombits() method so that randrange()
|
Optionally, implement a getrandombits() method so that randrange()
|
||||||
can cover arbitrarily large ranges.
|
can cover arbitrarily large ranges.
|
||||||
|
|
||||||
|
@ -615,156 +609,6 @@ class Random(_random.Random):
|
||||||
u = 1.0 - self.random()
|
u = 1.0 - self.random()
|
||||||
return alpha * pow(-_log(u), 1.0/beta)
|
return alpha * pow(-_log(u), 1.0/beta)
|
||||||
|
|
||||||
## -------------------- Wichmann-Hill -------------------
|
|
||||||
|
|
||||||
class WichmannHill(Random):
|
|
||||||
|
|
||||||
VERSION = 1 # used by getstate/setstate
|
|
||||||
|
|
||||||
def seed(self, a=None):
|
|
||||||
"""Initialize internal state from hashable object.
|
|
||||||
|
|
||||||
None or no argument seeds from current time or from an operating
|
|
||||||
system specific randomness source if available.
|
|
||||||
|
|
||||||
If a is not None or an int or long, hash(a) is used instead.
|
|
||||||
|
|
||||||
If a is an int or long, a is used directly. Distinct values between
|
|
||||||
0 and 27814431486575L inclusive are guaranteed to yield distinct
|
|
||||||
internal states (this guarantee is specific to the default
|
|
||||||
Wichmann-Hill generator).
|
|
||||||
"""
|
|
||||||
|
|
||||||
if a is None:
|
|
||||||
try:
|
|
||||||
a = int(_hexlify(_urandom(16)), 16)
|
|
||||||
except NotImplementedError:
|
|
||||||
import time
|
|
||||||
a = int(time.time() * 256) # use fractional seconds
|
|
||||||
|
|
||||||
if not isinstance(a, int):
|
|
||||||
a = hash(a)
|
|
||||||
|
|
||||||
a, x = divmod(a, 30268)
|
|
||||||
a, y = divmod(a, 30306)
|
|
||||||
a, z = divmod(a, 30322)
|
|
||||||
self._seed = int(x)+1, int(y)+1, int(z)+1
|
|
||||||
|
|
||||||
self.gauss_next = None
|
|
||||||
|
|
||||||
def random(self):
|
|
||||||
"""Get the next random number in the range [0.0, 1.0)."""
|
|
||||||
|
|
||||||
# Wichman-Hill random number generator.
|
|
||||||
#
|
|
||||||
# Wichmann, B. A. & Hill, I. D. (1982)
|
|
||||||
# Algorithm AS 183:
|
|
||||||
# An efficient and portable pseudo-random number generator
|
|
||||||
# Applied Statistics 31 (1982) 188-190
|
|
||||||
#
|
|
||||||
# see also:
|
|
||||||
# Correction to Algorithm AS 183
|
|
||||||
# Applied Statistics 33 (1984) 123
|
|
||||||
#
|
|
||||||
# McLeod, A. I. (1985)
|
|
||||||
# A remark on Algorithm AS 183
|
|
||||||
# Applied Statistics 34 (1985),198-200
|
|
||||||
|
|
||||||
# This part is thread-unsafe:
|
|
||||||
# BEGIN CRITICAL SECTION
|
|
||||||
x, y, z = self._seed
|
|
||||||
x = (171 * x) % 30269
|
|
||||||
y = (172 * y) % 30307
|
|
||||||
z = (170 * z) % 30323
|
|
||||||
self._seed = x, y, z
|
|
||||||
# END CRITICAL SECTION
|
|
||||||
|
|
||||||
# Note: on a platform using IEEE-754 double arithmetic, this can
|
|
||||||
# never return 0.0 (asserted by Tim; proof too long for a comment).
|
|
||||||
return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
|
|
||||||
|
|
||||||
def getstate(self):
|
|
||||||
"""Return internal state; can be passed to setstate() later."""
|
|
||||||
return self.VERSION, self._seed, self.gauss_next
|
|
||||||
|
|
||||||
def setstate(self, state):
|
|
||||||
"""Restore internal state from object returned by getstate()."""
|
|
||||||
version = state[0]
|
|
||||||
if version == 1:
|
|
||||||
version, self._seed, self.gauss_next = state
|
|
||||||
else:
|
|
||||||
raise ValueError("state with version %s passed to "
|
|
||||||
"Random.setstate() of version %s" %
|
|
||||||
(version, self.VERSION))
|
|
||||||
|
|
||||||
def jumpahead(self, n):
|
|
||||||
"""Act as if n calls to random() were made, but quickly.
|
|
||||||
|
|
||||||
n is an int, greater than or equal to 0.
|
|
||||||
|
|
||||||
Example use: If you have 2 threads and know that each will
|
|
||||||
consume no more than a million random numbers, create two Random
|
|
||||||
objects r1 and r2, then do
|
|
||||||
r2.setstate(r1.getstate())
|
|
||||||
r2.jumpahead(1000000)
|
|
||||||
Then r1 and r2 will use guaranteed-disjoint segments of the full
|
|
||||||
period.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not n >= 0:
|
|
||||||
raise ValueError("n must be >= 0")
|
|
||||||
x, y, z = self._seed
|
|
||||||
x = int(x * pow(171, n, 30269)) % 30269
|
|
||||||
y = int(y * pow(172, n, 30307)) % 30307
|
|
||||||
z = int(z * pow(170, n, 30323)) % 30323
|
|
||||||
self._seed = x, y, z
|
|
||||||
|
|
||||||
def __whseed(self, x=0, y=0, z=0):
|
|
||||||
"""Set the Wichmann-Hill seed from (x, y, z).
|
|
||||||
|
|
||||||
These must be integers in the range [0, 256).
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not type(x) == type(y) == type(z) == int:
|
|
||||||
raise TypeError('seeds must be integers')
|
|
||||||
if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
|
|
||||||
raise ValueError('seeds must be in range(0, 256)')
|
|
||||||
if 0 == x == y == z:
|
|
||||||
# Initialize from current time
|
|
||||||
import time
|
|
||||||
t = int(time.time() * 256)
|
|
||||||
t = int((t&0xffffff) ^ (t>>24))
|
|
||||||
t, x = divmod(t, 256)
|
|
||||||
t, y = divmod(t, 256)
|
|
||||||
t, z = divmod(t, 256)
|
|
||||||
# Zero is a poor seed, so substitute 1
|
|
||||||
self._seed = (x or 1, y or 1, z or 1)
|
|
||||||
|
|
||||||
self.gauss_next = None
|
|
||||||
|
|
||||||
def whseed(self, a=None):
|
|
||||||
"""Seed from hashable object's hash code.
|
|
||||||
|
|
||||||
None or no argument seeds from current time. It is not guaranteed
|
|
||||||
that objects with distinct hash codes lead to distinct internal
|
|
||||||
states.
|
|
||||||
|
|
||||||
This is obsolete, provided for compatibility with the seed routine
|
|
||||||
used prior to Python 2.1. Use the .seed() method instead.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if a is None:
|
|
||||||
self.__whseed()
|
|
||||||
return
|
|
||||||
a = hash(a)
|
|
||||||
a, x = divmod(a, 256)
|
|
||||||
a, y = divmod(a, 256)
|
|
||||||
a, z = divmod(a, 256)
|
|
||||||
x = (x + a) % 256 or 1
|
|
||||||
y = (y + a) % 256 or 1
|
|
||||||
z = (z + a) % 256 or 1
|
|
||||||
self.__whseed(x, y, z)
|
|
||||||
|
|
||||||
## --------------- Operating System Random Source ------------------
|
## --------------- Operating System Random Source ------------------
|
||||||
|
|
||||||
class SystemRandom(Random):
|
class SystemRandom(Random):
|
||||||
|
@ -789,10 +633,9 @@ class SystemRandom(Random):
|
||||||
x = int(_hexlify(_urandom(bytes)), 16)
|
x = int(_hexlify(_urandom(bytes)), 16)
|
||||||
return x >> (bytes * 8 - k) # trim excess bits
|
return x >> (bytes * 8 - k) # trim excess bits
|
||||||
|
|
||||||
def _stub(self, *args, **kwds):
|
def seed(self, *args, **kwds):
|
||||||
"Stub method. Not used for a system random number generator."
|
"Stub method. Not used for a system random number generator."
|
||||||
return None
|
return None
|
||||||
seed = jumpahead = _stub
|
|
||||||
|
|
||||||
def _notimplemented(self, *args, **kwds):
|
def _notimplemented(self, *args, **kwds):
|
||||||
"Method should not be called for a system random number generator."
|
"Method should not be called for a system random number generator."
|
||||||
|
@ -866,7 +709,6 @@ paretovariate = _inst.paretovariate
|
||||||
weibullvariate = _inst.weibullvariate
|
weibullvariate = _inst.weibullvariate
|
||||||
getstate = _inst.getstate
|
getstate = _inst.getstate
|
||||||
setstate = _inst.setstate
|
setstate = _inst.setstate
|
||||||
jumpahead = _inst.jumpahead
|
|
||||||
getrandbits = _inst.getrandbits
|
getrandbits = _inst.getrandbits
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -444,7 +444,7 @@ Subject: Re: PEP 255: Simple Generators
|
||||||
>>> roots = sets[:]
|
>>> roots = sets[:]
|
||||||
|
|
||||||
>>> import random
|
>>> import random
|
||||||
>>> gen = random.WichmannHill(42)
|
>>> gen = random.Random(42)
|
||||||
>>> while 1:
|
>>> while 1:
|
||||||
... for s in sets:
|
... for s in sets:
|
||||||
... print(" %s->%s" % (s, s.find()), end='')
|
... print(" %s->%s" % (s, s.find()), end='')
|
||||||
|
@ -458,29 +458,29 @@ Subject: Re: PEP 255: Simple Generators
|
||||||
... else:
|
... else:
|
||||||
... break
|
... break
|
||||||
A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->K L->L M->M
|
A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->K L->L M->M
|
||||||
merged D into G
|
merged I into A
|
||||||
A->A B->B C->C D->G E->E F->F G->G H->H I->I J->J K->K L->L M->M
|
A->A B->B C->C D->D E->E F->F G->G H->H I->A J->J K->K L->L M->M
|
||||||
merged C into F
|
merged D into C
|
||||||
A->A B->B C->F D->G E->E F->F G->G H->H I->I J->J K->K L->L M->M
|
A->A B->B C->C D->C E->E F->F G->G H->H I->A J->J K->K L->L M->M
|
||||||
|
merged K into H
|
||||||
|
A->A B->B C->C D->C E->E F->F G->G H->H I->A J->J K->H L->L M->M
|
||||||
merged L into A
|
merged L into A
|
||||||
A->A B->B C->F D->G E->E F->F G->G H->H I->I J->J K->K L->A M->M
|
A->A B->B C->C D->C E->E F->F G->G H->H I->A J->J K->H L->A M->M
|
||||||
merged H into E
|
merged E into A
|
||||||
A->A B->B C->F D->G E->E F->F G->G H->E I->I J->J K->K L->A M->M
|
A->A B->B C->C D->C E->A F->F G->G H->H I->A J->J K->H L->A M->M
|
||||||
merged B into E
|
merged B into G
|
||||||
A->A B->E C->F D->G E->E F->F G->G H->E I->I J->J K->K L->A M->M
|
A->A B->G C->C D->C E->A F->F G->G H->H I->A J->J K->H L->A M->M
|
||||||
|
merged A into F
|
||||||
|
A->F B->G C->C D->C E->F F->F G->G H->H I->F J->J K->H L->F M->M
|
||||||
|
merged H into G
|
||||||
|
A->F B->G C->C D->C E->F F->F G->G H->G I->F J->J K->G L->F M->M
|
||||||
|
merged F into J
|
||||||
|
A->J B->G C->C D->C E->J F->J G->G H->G I->J J->J K->G L->J M->M
|
||||||
|
merged M into C
|
||||||
|
A->J B->G C->C D->C E->J F->J G->G H->G I->J J->J K->G L->J M->C
|
||||||
merged J into G
|
merged J into G
|
||||||
A->A B->E C->F D->G E->E F->F G->G H->E I->I J->G K->K L->A M->M
|
A->G B->G C->C D->C E->G F->G G->G H->G I->G J->G K->G L->G M->C
|
||||||
merged E into G
|
merged C into G
|
||||||
A->A B->G C->F D->G E->G F->F G->G H->G I->I J->G K->K L->A M->M
|
|
||||||
merged M into G
|
|
||||||
A->A B->G C->F D->G E->G F->F G->G H->G I->I J->G K->K L->A M->G
|
|
||||||
merged I into K
|
|
||||||
A->A B->G C->F D->G E->G F->F G->G H->G I->K J->G K->K L->A M->G
|
|
||||||
merged K into A
|
|
||||||
A->A B->G C->F D->G E->G F->F G->G H->G I->A J->G K->A L->A M->G
|
|
||||||
merged F into A
|
|
||||||
A->A B->G C->A D->G E->G F->A G->G H->G I->A J->G K->A L->A M->G
|
|
||||||
merged A into G
|
|
||||||
A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G
|
A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -42,21 +42,6 @@ class TestBasicOps(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, self.gen.seed, 1, 2)
|
self.assertRaises(TypeError, self.gen.seed, 1, 2)
|
||||||
self.assertRaises(TypeError, type(self.gen), [])
|
self.assertRaises(TypeError, type(self.gen), [])
|
||||||
|
|
||||||
def test_jumpahead(self):
|
|
||||||
self.gen.seed()
|
|
||||||
state1 = self.gen.getstate()
|
|
||||||
self.gen.jumpahead(100)
|
|
||||||
state2 = self.gen.getstate() # s/b distinct from state1
|
|
||||||
self.assertNotEqual(state1, state2)
|
|
||||||
self.gen.jumpahead(100)
|
|
||||||
state3 = self.gen.getstate() # s/b distinct from state2
|
|
||||||
self.assertNotEqual(state2, state3)
|
|
||||||
|
|
||||||
self.assertRaises(TypeError, self.gen.jumpahead) # needs an arg
|
|
||||||
self.assertRaises(TypeError, self.gen.jumpahead, "ick") # wrong type
|
|
||||||
self.assertRaises(TypeError, self.gen.jumpahead, 2.3) # wrong type
|
|
||||||
self.assertRaises(TypeError, self.gen.jumpahead, 2, 3) # too many
|
|
||||||
|
|
||||||
def test_sample(self):
|
def test_sample(self):
|
||||||
# For the entire allowable range of 0 <= k <= N, validate that
|
# For the entire allowable range of 0 <= k <= N, validate that
|
||||||
# the sample is of the correct length and contains only unique items
|
# the sample is of the correct length and contains only unique items
|
||||||
|
@ -157,48 +142,6 @@ class TestBasicOps(unittest.TestCase):
|
||||||
f.close()
|
f.close()
|
||||||
self.assertEqual(r.randrange(1000), value)
|
self.assertEqual(r.randrange(1000), value)
|
||||||
|
|
||||||
class WichmannHill_TestBasicOps(TestBasicOps):
|
|
||||||
gen = random.WichmannHill()
|
|
||||||
|
|
||||||
def test_setstate_first_arg(self):
|
|
||||||
self.assertRaises(ValueError, self.gen.setstate, (2, None, None))
|
|
||||||
|
|
||||||
def test_strong_jumpahead(self):
|
|
||||||
# tests that jumpahead(n) semantics correspond to n calls to random()
|
|
||||||
N = 1000
|
|
||||||
s = self.gen.getstate()
|
|
||||||
self.gen.jumpahead(N)
|
|
||||||
r1 = self.gen.random()
|
|
||||||
# now do it the slow way
|
|
||||||
self.gen.setstate(s)
|
|
||||||
for i in range(N):
|
|
||||||
self.gen.random()
|
|
||||||
r2 = self.gen.random()
|
|
||||||
self.assertEqual(r1, r2)
|
|
||||||
|
|
||||||
def test_gauss_with_whseed(self):
|
|
||||||
# Ensure that the seed() method initializes all the hidden state. In
|
|
||||||
# particular, through 2.2.1 it failed to reset a piece of state used
|
|
||||||
# by (and only by) the .gauss() method.
|
|
||||||
|
|
||||||
for seed in 1, 12, 123, 1234, 12345, 123456, 654321:
|
|
||||||
self.gen.whseed(seed)
|
|
||||||
x1 = self.gen.random()
|
|
||||||
y1 = self.gen.gauss(0, 1)
|
|
||||||
|
|
||||||
self.gen.whseed(seed)
|
|
||||||
x2 = self.gen.random()
|
|
||||||
y2 = self.gen.gauss(0, 1)
|
|
||||||
|
|
||||||
self.assertEqual(x1, x2)
|
|
||||||
self.assertEqual(y1, y2)
|
|
||||||
|
|
||||||
def test_bigrand(self):
|
|
||||||
# Verify warnings are raised when randrange is too large for random()
|
|
||||||
with test_support.catch_warning():
|
|
||||||
warnings.filterwarnings("error", "Underlying random")
|
|
||||||
self.assertRaises(UserWarning, self.gen.randrange, 2**60)
|
|
||||||
|
|
||||||
class SystemRandom_TestBasicOps(TestBasicOps):
|
class SystemRandom_TestBasicOps(TestBasicOps):
|
||||||
gen = random.SystemRandom()
|
gen = random.SystemRandom()
|
||||||
|
|
||||||
|
@ -214,10 +157,6 @@ class SystemRandom_TestBasicOps(TestBasicOps):
|
||||||
# Doesn't need to do anything except not fail
|
# Doesn't need to do anything except not fail
|
||||||
self.gen.seed(100)
|
self.gen.seed(100)
|
||||||
|
|
||||||
def test_jumpahead(self):
|
|
||||||
# Doesn't need to do anything except not fail
|
|
||||||
self.gen.jumpahead(100)
|
|
||||||
|
|
||||||
def test_gauss(self):
|
def test_gauss(self):
|
||||||
self.gen.gauss_next = None
|
self.gen.gauss_next = None
|
||||||
self.gen.seed(100)
|
self.gen.seed(100)
|
||||||
|
@ -541,8 +480,7 @@ class TestModule(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
def test_main(verbose=None):
|
def test_main(verbose=None):
|
||||||
testclasses = [WichmannHill_TestBasicOps,
|
testclasses = [MersenneTwister_TestBasicOps,
|
||||||
MersenneTwister_TestBasicOps,
|
|
||||||
TestDistributions,
|
TestDistributions,
|
||||||
TestModule]
|
TestModule]
|
||||||
|
|
||||||
|
|
|
@ -352,6 +352,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Removed defunct parts of the random module (the Wichmann-Hill generator
|
||||||
|
and the jumpahead() method).
|
||||||
|
|
||||||
- Patch #467924: add ZipFile.extract() and ZipFile.extractall() in the
|
- Patch #467924: add ZipFile.extract() and ZipFile.extractall() in the
|
||||||
zipfile module.
|
zipfile module.
|
||||||
|
|
||||||
|
|
|
@ -369,72 +369,6 @@ random_setstate(RandomObject *self, PyObject *state)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Jumpahead should be a fast way advance the generator n-steps ahead, but
|
|
||||||
lacking a formula for that, the next best is to use n and the existing
|
|
||||||
state to create a new state far away from the original.
|
|
||||||
|
|
||||||
The generator uses constant spaced additive feedback, so shuffling the
|
|
||||||
state elements ought to produce a state which would not be encountered
|
|
||||||
(in the near term) by calls to random(). Shuffling is normally
|
|
||||||
implemented by swapping the ith element with another element ranging
|
|
||||||
from 0 to i inclusive. That allows the element to have the possibility
|
|
||||||
of not being moved. Since the goal is to produce a new, different
|
|
||||||
state, the swap element is ranged from 0 to i-1 inclusive. This assures
|
|
||||||
that each element gets moved at least once.
|
|
||||||
|
|
||||||
To make sure that consecutive calls to jumpahead(n) produce different
|
|
||||||
states (even in the rare case of involutory shuffles), i+1 is added to
|
|
||||||
each element at position i. Successive calls are then guaranteed to
|
|
||||||
have changing (growing) values as well as shuffled positions.
|
|
||||||
|
|
||||||
Finally, the self->index value is set to N so that the generator itself
|
|
||||||
kicks in on the next call to random(). This assures that all results
|
|
||||||
have been through the generator and do not just reflect alterations to
|
|
||||||
the underlying state.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
random_jumpahead(RandomObject *self, PyObject *n)
|
|
||||||
{
|
|
||||||
long i, j;
|
|
||||||
PyObject *iobj;
|
|
||||||
PyObject *remobj;
|
|
||||||
unsigned long *mt, tmp;
|
|
||||||
|
|
||||||
if (!PyLong_Check(n)) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "jumpahead requires an "
|
|
||||||
"integer, not '%s'",
|
|
||||||
Py_TYPE(n)->tp_name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mt = self->state;
|
|
||||||
for (i = N-1; i > 1; i--) {
|
|
||||||
iobj = PyLong_FromLong(i);
|
|
||||||
if (iobj == NULL)
|
|
||||||
return NULL;
|
|
||||||
remobj = PyNumber_Remainder(n, iobj);
|
|
||||||
Py_DECREF(iobj);
|
|
||||||
if (remobj == NULL)
|
|
||||||
return NULL;
|
|
||||||
j = PyLong_AsLong(remobj);
|
|
||||||
Py_DECREF(remobj);
|
|
||||||
if (j == -1L && PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
tmp = mt[i];
|
|
||||||
mt[i] = mt[j];
|
|
||||||
mt[j] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < N; i++)
|
|
||||||
mt[i] += i+1;
|
|
||||||
|
|
||||||
self->index = N;
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
random_getrandbits(RandomObject *self, PyObject *args)
|
random_getrandbits(RandomObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -506,9 +440,6 @@ static PyMethodDef random_methods[] = {
|
||||||
PyDoc_STR("getstate() -> tuple containing the current state.")},
|
PyDoc_STR("getstate() -> tuple containing the current state.")},
|
||||||
{"setstate", (PyCFunction)random_setstate, METH_O,
|
{"setstate", (PyCFunction)random_setstate, METH_O,
|
||||||
PyDoc_STR("setstate(state) -> None. Restores generator state.")},
|
PyDoc_STR("setstate(state) -> None. Restores generator state.")},
|
||||||
{"jumpahead", (PyCFunction)random_jumpahead, METH_O,
|
|
||||||
PyDoc_STR("jumpahead(int) -> None. Create new state from "
|
|
||||||
"existing state and integer.")},
|
|
||||||
{"getrandbits", (PyCFunction)random_getrandbits, METH_VARARGS,
|
{"getrandbits", (PyCFunction)random_getrandbits, METH_VARARGS,
|
||||||
PyDoc_STR("getrandbits(k) -> x. Generates a long int with "
|
PyDoc_STR("getrandbits(k) -> x. Generates a long int with "
|
||||||
"k random bits.")},
|
"k random bits.")},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue