blob: d4c07e3260d3ebdf528cf6d22c2ce150a3ebaf12 [file] [log] [blame]
Guido van Rossume7b146f2000-02-04 15:28:42 +00001"""Wichman-Hill random number generator.
2
3Wichmann, B. A. & Hill, I. D. (1982)
Tim Peterse1190062001-01-15 03:34:38 +00004Algorithm AS 183:
Guido van Rossume7b146f2000-02-04 15:28:42 +00005An efficient and portable pseudo-random number generator
6Applied Statistics 31 (1982) 188-190
7
Tim Peterse1190062001-01-15 03:34:38 +00008see also:
Guido van Rossume7b146f2000-02-04 15:28:42 +00009 Correction to Algorithm AS 183
Tim Peterse1190062001-01-15 03:34:38 +000010 Applied Statistics 33 (1984) 123
Guido van Rossume7b146f2000-02-04 15:28:42 +000011
12 McLeod, A. I. (1985)
Tim Peterse1190062001-01-15 03:34:38 +000013 A remark on Algorithm AS 183
Guido van Rossume7b146f2000-02-04 15:28:42 +000014 Applied Statistics 34 (1985),198-200
Guido van Rossumc6360141990-10-13 19:23:40 +000015
16
Guido van Rossume7b146f2000-02-04 15:28:42 +000017USE:
Tim Peterse1190062001-01-15 03:34:38 +000018whrandom.random() yields double precision random numbers
Guido van Rossume7b146f2000-02-04 15:28:42 +000019 uniformly distributed between 0 and 1.
20
21whrandom.seed(x, y, z) must be called before whrandom.random()
22 to seed the generator
23
24There is also an interface to create multiple independent
25random generators, and to choose from other ranges.
Guido van Rossumc6360141990-10-13 19:23:40 +000026
27
Guido van Rossume7b146f2000-02-04 15:28:42 +000028
29Multi-threading note: the random number generator used here is not
30thread-safe; it is possible that nearly simultaneous calls in
31different theads return the same random value. To avoid this, you
32have to use a lock around all calls. (I didn't want to slow this
33down in the serial case by using a lock here.)
34"""
35
Guido van Rossum98d9fd32000-02-28 15:12:25 +000036# Translated by Guido van Rossum from C source provided by
37# Adrian Baddeley.
38
Fred Drake6e997042002-04-10 01:45:11 +000039import warnings
40warnings.warn("the whrandom module is deprecated; please use random",
41 DeprecationWarning)
42del warnings
43
Guido van Rossum98d9fd32000-02-28 15:12:25 +000044
Guido van Rossum2db91351992-10-18 17:09:59 +000045class whrandom:
Tim Peterse1190062001-01-15 03:34:38 +000046 def __init__(self, x = 0, y = 0, z = 0):
47 """Initialize an instance.
48 Without arguments, initialize from current time.
49 With arguments (x, y, z), initialize from them."""
50 self.seed(x, y, z)
Guido van Rossume7b146f2000-02-04 15:28:42 +000051
Tim Peterse1190062001-01-15 03:34:38 +000052 def seed(self, x = 0, y = 0, z = 0):
53 """Set the seed from (x, y, z).
54 These must be integers in the range [0, 256)."""
55 if not type(x) == type(y) == type(z) == type(0):
56 raise TypeError, 'seeds must be integers'
57 if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
58 raise ValueError, 'seeds must be in range(0, 256)'
59 if 0 == x == y == z:
60 # Initialize from current time
61 import time
62 t = long(time.time() * 256)
63 t = int((t&0xffffff) ^ (t>>24))
64 t, x = divmod(t, 256)
65 t, y = divmod(t, 256)
66 t, z = divmod(t, 256)
67 # Zero is a poor seed, so substitute 1
68 self._seed = (x or 1, y or 1, z or 1)
Guido van Rossume7b146f2000-02-04 15:28:42 +000069
Tim Peterse1190062001-01-15 03:34:38 +000070 def random(self):
71 """Get the next random number in the range [0.0, 1.0)."""
72 # This part is thread-unsafe:
73 # BEGIN CRITICAL SECTION
74 x, y, z = self._seed
75 #
76 x = (171 * x) % 30269
77 y = (172 * y) % 30307
78 z = (170 * z) % 30323
79 #
80 self._seed = x, y, z
81 # END CRITICAL SECTION
82 #
83 return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
Guido van Rossume7b146f2000-02-04 15:28:42 +000084
Tim Peterse1190062001-01-15 03:34:38 +000085 def uniform(self, a, b):
86 """Get a random number in the range [a, b)."""
87 return a + (b-a) * self.random()
Guido van Rossume7b146f2000-02-04 15:28:42 +000088
Tim Peterse1190062001-01-15 03:34:38 +000089 def randint(self, a, b):
90 """Get a random integer in the range [a, b] including
91 both end points.
Fred Drake0412e492000-06-30 19:33:35 +000092
Tim Peterse1190062001-01-15 03:34:38 +000093 (Deprecated; use randrange below.)"""
94 return self.randrange(a, b+1)
Guido van Rossume7b146f2000-02-04 15:28:42 +000095
Tim Peterse1190062001-01-15 03:34:38 +000096 def choice(self, seq):
97 """Choose a random element from a non-empty sequence."""
98 return seq[int(self.random() * len(seq))]
Guido van Rossume7b146f2000-02-04 15:28:42 +000099
Tim Peterse1190062001-01-15 03:34:38 +0000100 def randrange(self, start, stop=None, step=1, int=int, default=None):
101 """Choose a random item from range(start, stop[, step]).
Fred Drake0412e492000-06-30 19:33:35 +0000102
Tim Peterse1190062001-01-15 03:34:38 +0000103 This fixes the problem with randint() which includes the
104 endpoint; in Python this is usually not what you want.
105 Do not supply the 'int' and 'default' arguments."""
106 # This code is a bit messy to make it fast for the
107 # common case while still doing adequate error checking
108 istart = int(start)
109 if istart != start:
110 raise ValueError, "non-integer arg 1 for randrange()"
111 if stop is default:
112 if istart > 0:
113 return int(self.random() * istart)
114 raise ValueError, "empty range for randrange()"
115 istop = int(stop)
116 if istop != stop:
117 raise ValueError, "non-integer stop for randrange()"
118 if step == 1:
119 if istart < istop:
120 return istart + int(self.random() *
121 (istop - istart))
122 raise ValueError, "empty range for randrange()"
123 istep = int(step)
124 if istep != step:
125 raise ValueError, "non-integer step for randrange()"
126 if istep > 0:
127 n = (istop - istart + istep - 1) / istep
128 elif istep < 0:
129 n = (istop - istart + istep + 1) / istep
130 else:
131 raise ValueError, "zero step for randrange()"
Guido van Rossum187f1541998-07-31 13:39:44 +0000132
Tim Peterse1190062001-01-15 03:34:38 +0000133 if n <= 0:
134 raise ValueError, "empty range for randrange()"
135 return istart + istep*int(self.random() * n)
Guido van Rossumc6360141990-10-13 19:23:40 +0000136
137
138# Initialize from the current time
Guido van Rossum7bc817d1993-12-17 15:25:27 +0000139_inst = whrandom()
Guido van Rossum2db91351992-10-18 17:09:59 +0000140seed = _inst.seed
141random = _inst.random
142uniform = _inst.uniform
143randint = _inst.randint
144choice = _inst.choice
Guido van Rossum187f1541998-07-31 13:39:44 +0000145randrange = _inst.randrange