"""Wichman-Hill random number generator.
Wichmann, B. A. & Hill, I. D. (1982)
An efficient and portable pseudo-random number generator
Applied Statistics 31 (1982) 188-190
Correction to Algorithm AS 183
Applied Statistics 33 (1984) 123
A remark on Algorithm AS 183
Applied Statistics 34 (1985),198-200
whrandom.random() yields double precision random numbers
uniformly distributed between 0 and 1.
whrandom.seed(x, y, z) must be called before whrandom.random()
There is also an interface to create multiple independent
random generators, and to choose from other ranges.
Multi-threading note: the random number generator used here is not
thread-safe; it is possible that nearly simultaneous calls in
different theads return the same random value. To avoid this, you
have to use a lock around all calls. (I didn't want to slow this
down in the serial case by using a lock here.)
warnings
.warn("the whrandom module is deprecated; please use the random module",
# Translated by Guido van Rossum from C source provided by
def __init__(self
, x
= 0, y
= 0, z
= 0):
"""Initialize an instance.
Without arguments, initialize from current time.
With arguments (x, y, z), initialize from them."""
def seed(self
, x
= 0, y
= 0, z
= 0):
"""Set the seed from (x, y, z).
These must be integers in the range [0, 256)."""
if not type(x
) == type(y
) == type(z
) == type(0):
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)'
# Initialize from current time
t
= long(time
.time() * 256)
t
= int((t
&0xffffff) ^
(t
>>24))
# Zero is a poor seed, so substitute 1
self
._seed
= (x
or 1, y
or 1, z
or 1)
"""Get the next random number in the range [0.0, 1.0)."""
# This part is thread-unsafe:
return (x
/30269.0 + y
/30307.0 + z
/30323.0) % 1.0
"""Get a random number in the range [a, b)."""
return a
+ (b
-a
) * self
.random()
"""Get a random integer in the range [a, b] including
(Deprecated; use randrange below.)"""
return self
.randrange(a
, b
+1)
"""Choose a random element from a non-empty sequence."""
return seq
[int(self
.random() * len(seq
))]
def randrange(self
, start
, stop
=None, step
=1, int=int, default
=None):
"""Choose a random item from range(start, stop[, step]).
This fixes the problem with randint() which includes the
endpoint; in Python this is usually not what you want.
Do not supply the 'int' and 'default' arguments."""
# This code is a bit messy to make it fast for the
# common case while still doing adequate error checking
raise ValueError, "non-integer arg 1 for randrange()"
return int(self
.random() * istart
)
raise ValueError, "empty range for randrange()"
raise ValueError, "non-integer stop for randrange()"
return istart
+ int(self
.random() *
raise ValueError, "empty range for randrange()"
raise ValueError, "non-integer step for randrange()"
n
= (istop
- istart
+ istep
- 1) / istep
n
= (istop
- istart
+ istep
+ 1) / istep
raise ValueError, "zero step for randrange()"
raise ValueError, "empty range for randrange()"
return istart
+ istep
*int(self
.random() * n
)
# Initialize from the current time
randrange
= _inst
.randrange