[Python-checkins] CVS: python/dist/src/Lib random.py,1.16,1.17
Tim Peters
tim_one@users.sourceforge.net
Wed, 24 Jan 2001 22:23:20 -0800
Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv11428/python/dist/src/Lib
Modified Files:
random.py
Log Message:
Fix bugs introduced by rewrite (in particular, time-based initialization
got broken). Also added new method .jumpahead(N). This finally gives us
a semi-decent answer to how Python's RNGs can be used safely and efficiently
in multithreaded programs (although it requires the user to use the new
machinery!).
Index: random.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/random.py,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -r1.16 -r1.17
*** random.py 2001/01/25 03:36:25 1.16
--- random.py 2001/01/25 06:23:18 1.17
***************
*** 73,78 ****
# Specific to Wichmann-Hill generator. Subclasses wishing to use a
! # different core generator should override seed(), random(), getstate()
! # and setstate().
def __whseed(self, x=0, y=0, z=0):
--- 73,78 ----
# Specific to Wichmann-Hill generator. Subclasses wishing to use a
! # different core generator should override the seed(), random(),
! # getstate(), setstate(), and jumpahead() methods.
def __whseed(self, x=0, y=0, z=0):
***************
*** 105,108 ****
--- 105,109 ----
if a is None:
self.__whseed()
+ return
a = hash(a)
a, x = divmod(a, 256)
***************
*** 116,124 ****
def getstate(self):
"""Return internal state; can be passed to setstate() later."""
-
return self.VERSION, self._seed, self.gauss_next
def __getstate__(self): # for pickle
! self.getstate()
def setstate(self, state):
--- 117,124 ----
def getstate(self):
"""Return internal state; can be passed to setstate() later."""
return self.VERSION, self._seed, self.gauss_next
def __getstate__(self): # for pickle
! return self.getstate()
def setstate(self, state):
***************
*** 135,138 ****
--- 135,160 ----
self.setstate(state)
+ 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 random(self):
"""Get the next random number in the range [0.0, 1.0)."""
***************
*** 472,475 ****
--- 494,508 ----
(avg, stddev, smallest, largest)
+ s = getstate()
+ N = 1019
+ jumpahead(N)
+ r1 = random()
+ setstate(s)
+ for i in range(N): # now do it the slow way
+ random()
+ r2 = random()
+ if r1 != r2:
+ raise ValueError("jumpahead test failed " + `(N, r1, r2)`)
+
def _test(N=200):
print 'TWOPI =', TWOPI
***************
*** 516,519 ****
--- 549,553 ----
getstate = _inst.getstate
setstate = _inst.setstate
+ jumpahead = _inst.jumpahead
if __name__ == '__main__':