blob: 427b73179c699d0e7d3e4720dc5f6bbc831b5fe7 [file] [log] [blame]
Guido van Rossume7b146f2000-02-04 15:28:42 +00001"""Random variable generators.
Guido van Rossumff03b1a1994-03-09 12:55:02 +00002
Tim Petersd7b5e882001-01-25 03:36:26 +00003 integers
4 --------
5 uniform within range
6
7 sequences
8 ---------
9 pick random element
10 generate random permutation
11
Guido van Rossume7b146f2000-02-04 15:28:42 +000012 distributions on the real line:
13 ------------------------------
Tim Petersd7b5e882001-01-25 03:36:26 +000014 uniform
Guido van Rossume7b146f2000-02-04 15:28:42 +000015 normal (Gaussian)
16 lognormal
17 negative exponential
18 gamma
19 beta
Guido van Rossumff03b1a1994-03-09 12:55:02 +000020
Guido van Rossume7b146f2000-02-04 15:28:42 +000021 distributions on the circle (angles 0 to 2pi)
22 ---------------------------------------------
23 circular uniform
24 von Mises
25
26Translated from anonymously contributed C/C++ source.
27
Tim Peterse360d952001-01-26 10:00:39 +000028Multi-threading note: the random number generator used here is not thread-
29safe; it is possible that two calls return the same random value. However,
30you can instantiate a different instance of Random() in each thread to get
31generators that don't share state, then use .setstate() and .jumpahead() to
32move the generators to disjoint segments of the full period. For example,
33
34def create_generators(num, delta, firstseed=None):
35 ""\"Return list of num distinct generators.
36 Each generator has its own unique segment of delta elements from
37 Random.random()'s full period.
38 Seed the first generator with optional arg firstseed (default is
39 None, to seed from current time).
40 ""\"
41
42 from random import Random
43 g = Random(firstseed)
44 result = [g]
45 for i in range(num - 1):
46 laststate = g.getstate()
47 g = Random()
48 g.setstate(laststate)
49 g.jumpahead(delta)
50 result.append(g)
51 return result
52
53gens = create_generators(10, 1000000)
54
55That creates 10 distinct generators, which can be passed out to 10 distinct
56threads. The generators don't share state so can be called safely in
57parallel. So long as no thread calls its g.random() more than a million
58times (the second argument to create_generators), the sequences seen by
59each thread will not overlap.
60
61The period of the underlying Wichmann-Hill generator is 6,953,607,871,644,
62and that limits how far this technique can be pushed.
63
64Just for fun, note that since we know the period, .jumpahead() can also be
65used to "move backward in time":
66
67>>> g = Random(42) # arbitrary
68>>> g.random()
Tim Peters0de88fc2001-02-01 04:59:18 +0000690.25420336316883324
Tim Peterse360d952001-01-26 10:00:39 +000070>>> g.jumpahead(6953607871644L - 1) # move *back* one
71>>> g.random()
Tim Peters0de88fc2001-02-01 04:59:18 +0000720.25420336316883324
Guido van Rossume7b146f2000-02-04 15:28:42 +000073"""
Tim Petersd7b5e882001-01-25 03:36:26 +000074# XXX The docstring sucks.
Guido van Rossumd03e1191998-05-29 17:51:31 +000075
Tim Petersd7b5e882001-01-25 03:36:26 +000076from math import log as _log, exp as _exp, pi as _pi, e as _e
77from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
Guido van Rossumff03b1a1994-03-09 12:55:02 +000078
Tim Petersd7b5e882001-01-25 03:36:26 +000079def _verify(name, expected):
Tim Peters0c9886d2001-01-15 01:18:21 +000080 computed = eval(name)
81 if abs(computed - expected) > 1e-7:
Tim Petersd7b5e882001-01-25 03:36:26 +000082 raise ValueError(
83 "computed value for %s deviates too much "
84 "(computed %g, expected %g)" % (name, computed, expected))
85
86NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)
87_verify('NV_MAGICCONST', 1.71552776992141)
88
89TWOPI = 2.0*_pi
90_verify('TWOPI', 6.28318530718)
91
92LOG4 = _log(4.0)
93_verify('LOG4', 1.38629436111989)
94
95SG_MAGICCONST = 1.0 + _log(4.5)
96_verify('SG_MAGICCONST', 2.50407739677627)
97
98del _verify
99
100# Translated by Guido van Rossum from C source provided by
101# Adrian Baddeley.
102
103class Random:
104
105 VERSION = 1 # used by getstate/setstate
106
107 def __init__(self, x=None):
108 """Initialize an instance.
109
110 Optional argument x controls seeding, as for Random.seed().
111 """
112
113 self.seed(x)
114 self.gauss_next = None
115
Tim Peterscd804102001-01-25 20:25:57 +0000116## -------------------- core generator -------------------
117
Tim Petersd7b5e882001-01-25 03:36:26 +0000118 # Specific to Wichmann-Hill generator. Subclasses wishing to use a
Tim Petersd52269b2001-01-25 06:23:18 +0000119 # different core generator should override the seed(), random(),
Tim Peterscd804102001-01-25 20:25:57 +0000120 # getstate(), setstate() and jumpahead() methods.
Tim Petersd7b5e882001-01-25 03:36:26 +0000121
Tim Peters0de88fc2001-02-01 04:59:18 +0000122 def seed(self, a=None):
123 """Initialize internal state from hashable object.
Tim Petersd7b5e882001-01-25 03:36:26 +0000124
Tim Peters0de88fc2001-02-01 04:59:18 +0000125 None or no argument seeds from current time.
126
127 If a is not None or an int or long, hash(a) is instead.
128
129 If a is an int or long, a is used directly. Distinct values between
130 0 and 27814431486575L inclusive are guaranteed to yield distinct
131 internal states (this guarantee is specific to the default
132 Wichmann-Hill generator).
Tim Petersd7b5e882001-01-25 03:36:26 +0000133 """
134
Tim Peters0de88fc2001-02-01 04:59:18 +0000135 if a is None:
Tim Petersd7b5e882001-01-25 03:36:26 +0000136 # Initialize from current time
137 import time
Tim Peters0de88fc2001-02-01 04:59:18 +0000138 a = long(time.time() * 256)
139
140 if type(a) not in (type(3), type(3L)):
141 a = hash(a)
142
143 a, x = divmod(a, 30268)
144 a, y = divmod(a, 30306)
145 a, z = divmod(a, 30322)
146 self._seed = int(x)+1, int(y)+1, int(z)+1
Tim Petersd7b5e882001-01-25 03:36:26 +0000147
Tim Petersd7b5e882001-01-25 03:36:26 +0000148 def random(self):
149 """Get the next random number in the range [0.0, 1.0)."""
150
151 # Wichman-Hill random number generator.
152 #
153 # Wichmann, B. A. & Hill, I. D. (1982)
154 # Algorithm AS 183:
155 # An efficient and portable pseudo-random number generator
156 # Applied Statistics 31 (1982) 188-190
157 #
158 # see also:
159 # Correction to Algorithm AS 183
160 # Applied Statistics 33 (1984) 123
161 #
162 # McLeod, A. I. (1985)
163 # A remark on Algorithm AS 183
164 # Applied Statistics 34 (1985),198-200
165
166 # This part is thread-unsafe:
167 # BEGIN CRITICAL SECTION
168 x, y, z = self._seed
169 x = (171 * x) % 30269
170 y = (172 * y) % 30307
171 z = (170 * z) % 30323
172 self._seed = x, y, z
173 # END CRITICAL SECTION
174
175 # Note: on a platform using IEEE-754 double arithmetic, this can
176 # never return 0.0 (asserted by Tim; proof too long for a comment).
177 return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
178
Tim Peterscd804102001-01-25 20:25:57 +0000179 def getstate(self):
180 """Return internal state; can be passed to setstate() later."""
181 return self.VERSION, self._seed, self.gauss_next
182
183 def setstate(self, state):
184 """Restore internal state from object returned by getstate()."""
185 version = state[0]
186 if version == 1:
187 version, self._seed, self.gauss_next = state
188 else:
189 raise ValueError("state with version %s passed to "
190 "Random.setstate() of version %s" %
191 (version, self.VERSION))
192
193 def jumpahead(self, n):
194 """Act as if n calls to random() were made, but quickly.
195
196 n is an int, greater than or equal to 0.
197
198 Example use: If you have 2 threads and know that each will
199 consume no more than a million random numbers, create two Random
200 objects r1 and r2, then do
201 r2.setstate(r1.getstate())
202 r2.jumpahead(1000000)
203 Then r1 and r2 will use guaranteed-disjoint segments of the full
204 period.
205 """
206
207 if not n >= 0:
208 raise ValueError("n must be >= 0")
209 x, y, z = self._seed
210 x = int(x * pow(171, n, 30269)) % 30269
211 y = int(y * pow(172, n, 30307)) % 30307
212 z = int(z * pow(170, n, 30323)) % 30323
213 self._seed = x, y, z
214
Tim Peters0de88fc2001-02-01 04:59:18 +0000215 def __whseed(self, x=0, y=0, z=0):
216 """Set the Wichmann-Hill seed from (x, y, z).
217
218 These must be integers in the range [0, 256).
219 """
220
221 if not type(x) == type(y) == type(z) == type(0):
222 raise TypeError('seeds must be integers')
223 if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
224 raise ValueError('seeds must be in range(0, 256)')
225 if 0 == x == y == z:
226 # Initialize from current time
227 import time
228 t = long(time.time() * 256)
229 t = int((t&0xffffff) ^ (t>>24))
230 t, x = divmod(t, 256)
231 t, y = divmod(t, 256)
232 t, z = divmod(t, 256)
233 # Zero is a poor seed, so substitute 1
234 self._seed = (x or 1, y or 1, z or 1)
235
236 def whseed(self, a=None):
237 """Seed from hashable object's hash code.
238
239 None or no argument seeds from current time. It is not guaranteed
240 that objects with distinct hash codes lead to distinct internal
241 states.
242
243 This is obsolete, provided for compatibility with the seed routine
244 used prior to Python 2.1. Use the .seed() method instead.
245 """
246
247 if a is None:
248 self.__whseed()
249 return
250 a = hash(a)
251 a, x = divmod(a, 256)
252 a, y = divmod(a, 256)
253 a, z = divmod(a, 256)
254 x = (x + a) % 256 or 1
255 y = (y + a) % 256 or 1
256 z = (z + a) % 256 or 1
257 self.__whseed(x, y, z)
258
Tim Peterscd804102001-01-25 20:25:57 +0000259## ---- Methods below this point do not need to be overridden when
260## ---- subclassing for the purpose of using a different core generator.
261
262## -------------------- pickle support -------------------
263
264 def __getstate__(self): # for pickle
265 return self.getstate()
266
267 def __setstate__(self, state): # for pickle
268 self.setstate(state)
269
270## -------------------- integer methods -------------------
271
Tim Petersd7b5e882001-01-25 03:36:26 +0000272 def randrange(self, start, stop=None, step=1, int=int, default=None):
273 """Choose a random item from range(start, stop[, step]).
274
275 This fixes the problem with randint() which includes the
276 endpoint; in Python this is usually not what you want.
277 Do not supply the 'int' and 'default' arguments.
278 """
279
280 # This code is a bit messy to make it fast for the
281 # common case while still doing adequate error checking
282 istart = int(start)
283 if istart != start:
284 raise ValueError, "non-integer arg 1 for randrange()"
285 if stop is default:
286 if istart > 0:
287 return int(self.random() * istart)
288 raise ValueError, "empty range for randrange()"
289 istop = int(stop)
290 if istop != stop:
291 raise ValueError, "non-integer stop for randrange()"
292 if step == 1:
293 if istart < istop:
294 return istart + int(self.random() *
295 (istop - istart))
296 raise ValueError, "empty range for randrange()"
297 istep = int(step)
298 if istep != step:
299 raise ValueError, "non-integer step for randrange()"
300 if istep > 0:
301 n = (istop - istart + istep - 1) / istep
302 elif istep < 0:
303 n = (istop - istart + istep + 1) / istep
304 else:
305 raise ValueError, "zero step for randrange()"
306
307 if n <= 0:
308 raise ValueError, "empty range for randrange()"
309 return istart + istep*int(self.random() * n)
310
311 def randint(self, a, b):
Tim Peterscd804102001-01-25 20:25:57 +0000312 """Return random integer in range [a, b], including both end points.
Tim Petersd7b5e882001-01-25 03:36:26 +0000313
Tim Peterscd804102001-01-25 20:25:57 +0000314 (Deprecated; use randrange(a, b+1).)
Tim Petersd7b5e882001-01-25 03:36:26 +0000315 """
316
317 return self.randrange(a, b+1)
318
Tim Peterscd804102001-01-25 20:25:57 +0000319## -------------------- sequence methods -------------------
320
Tim Petersd7b5e882001-01-25 03:36:26 +0000321 def choice(self, seq):
322 """Choose a random element from a non-empty sequence."""
323 return seq[int(self.random() * len(seq))]
324
325 def shuffle(self, x, random=None, int=int):
326 """x, random=random.random -> shuffle list x in place; return None.
327
328 Optional arg random is a 0-argument function returning a random
329 float in [0.0, 1.0); by default, the standard random.random.
330
331 Note that for even rather small len(x), the total number of
332 permutations of x is larger than the period of most random number
333 generators; this implies that "most" permutations of a long
334 sequence can never be generated.
335 """
336
337 if random is None:
338 random = self.random
339 for i in xrange(len(x)-1, 0, -1):
Tim Peterscd804102001-01-25 20:25:57 +0000340 # pick an element in x[:i+1] with which to exchange x[i]
Tim Petersd7b5e882001-01-25 03:36:26 +0000341 j = int(random() * (i+1))
342 x[i], x[j] = x[j], x[i]
343
Tim Peterscd804102001-01-25 20:25:57 +0000344## -------------------- real-valued distributions -------------------
345
346## -------------------- uniform distribution -------------------
Tim Petersd7b5e882001-01-25 03:36:26 +0000347
348 def uniform(self, a, b):
349 """Get a random number in the range [a, b)."""
350 return a + (b-a) * self.random()
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000351
Tim Peterscd804102001-01-25 20:25:57 +0000352## -------------------- normal distribution --------------------
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000353
Tim Petersd7b5e882001-01-25 03:36:26 +0000354 def normalvariate(self, mu, sigma):
355 # mu = mean, sigma = standard deviation
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000356
Tim Petersd7b5e882001-01-25 03:36:26 +0000357 # Uses Kinderman and Monahan method. Reference: Kinderman,
358 # A.J. and Monahan, J.F., "Computer generation of random
359 # variables using the ratio of uniform deviates", ACM Trans
360 # Math Software, 3, (1977), pp257-260.
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000361
Tim Petersd7b5e882001-01-25 03:36:26 +0000362 random = self.random
Tim Peters0c9886d2001-01-15 01:18:21 +0000363 while 1:
364 u1 = random()
365 u2 = random()
Tim Petersd7b5e882001-01-25 03:36:26 +0000366 z = NV_MAGICCONST*(u1-0.5)/u2
367 zz = z*z/4.0
368 if zz <= -_log(u2):
369 break
370 return mu + z*sigma
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000371
Tim Peterscd804102001-01-25 20:25:57 +0000372## -------------------- lognormal distribution --------------------
Tim Petersd7b5e882001-01-25 03:36:26 +0000373
374 def lognormvariate(self, mu, sigma):
375 return _exp(self.normalvariate(mu, sigma))
376
Tim Peterscd804102001-01-25 20:25:57 +0000377## -------------------- circular uniform --------------------
Tim Petersd7b5e882001-01-25 03:36:26 +0000378
379 def cunifvariate(self, mean, arc):
380 # mean: mean angle (in radians between 0 and pi)
381 # arc: range of distribution (in radians between 0 and pi)
382
383 return (mean + arc * (self.random() - 0.5)) % _pi
384
Tim Peterscd804102001-01-25 20:25:57 +0000385## -------------------- exponential distribution --------------------
Tim Petersd7b5e882001-01-25 03:36:26 +0000386
387 def expovariate(self, lambd):
388 # lambd: rate lambd = 1/mean
389 # ('lambda' is a Python reserved word)
390
391 random = self.random
Tim Peters0c9886d2001-01-15 01:18:21 +0000392 u = random()
393 while u <= 1e-7:
394 u = random()
Tim Petersd7b5e882001-01-25 03:36:26 +0000395 return -_log(u)/lambd
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000396
Tim Peterscd804102001-01-25 20:25:57 +0000397## -------------------- von Mises distribution --------------------
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000398
Tim Petersd7b5e882001-01-25 03:36:26 +0000399 def vonmisesvariate(self, mu, kappa):
400 # mu: mean angle (in radians between 0 and 2*pi)
401 # kappa: concentration parameter kappa (>= 0)
402 # if kappa = 0 generate uniform random angle
403
404 # Based upon an algorithm published in: Fisher, N.I.,
405 # "Statistical Analysis of Circular Data", Cambridge
406 # University Press, 1993.
407
408 # Thanks to Magnus Kessler for a correction to the
409 # implementation of step 4.
410
411 random = self.random
412 if kappa <= 1e-6:
413 return TWOPI * random()
414
415 a = 1.0 + _sqrt(1.0 + 4.0 * kappa * kappa)
416 b = (a - _sqrt(2.0 * a))/(2.0 * kappa)
417 r = (1.0 + b * b)/(2.0 * b)
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000418
Tim Peters0c9886d2001-01-15 01:18:21 +0000419 while 1:
Tim Peters0c9886d2001-01-15 01:18:21 +0000420 u1 = random()
Tim Petersd7b5e882001-01-25 03:36:26 +0000421
422 z = _cos(_pi * u1)
423 f = (1.0 + r * z)/(r + z)
424 c = kappa * (r - f)
425
426 u2 = random()
427
428 if not (u2 >= c * (2.0 - c) and u2 > c * _exp(1.0 - c)):
Tim Peters0c9886d2001-01-15 01:18:21 +0000429 break
Tim Petersd7b5e882001-01-25 03:36:26 +0000430
431 u3 = random()
432 if u3 > 0.5:
433 theta = (mu % TWOPI) + _acos(f)
434 else:
435 theta = (mu % TWOPI) - _acos(f)
436
437 return theta
438
Tim Peterscd804102001-01-25 20:25:57 +0000439## -------------------- gamma distribution --------------------
Tim Petersd7b5e882001-01-25 03:36:26 +0000440
441 def gammavariate(self, alpha, beta):
442 # beta times standard gamma
443 ainv = _sqrt(2.0 * alpha - 1.0)
444 return beta * self.stdgamma(alpha, ainv, alpha - LOG4, alpha + ainv)
445
446 def stdgamma(self, alpha, ainv, bbb, ccc):
447 # ainv = sqrt(2 * alpha - 1)
448 # bbb = alpha - log(4)
449 # ccc = alpha + ainv
450
451 random = self.random
452 if alpha <= 0.0:
453 raise ValueError, 'stdgamma: alpha must be > 0.0'
454
455 if alpha > 1.0:
456
457 # Uses R.C.H. Cheng, "The generation of Gamma
458 # variables with non-integral shape parameters",
459 # Applied Statistics, (1977), 26, No. 1, p71-74
460
461 while 1:
462 u1 = random()
463 u2 = random()
464 v = _log(u1/(1.0-u1))/ainv
465 x = alpha*_exp(v)
466 z = u1*u1*u2
467 r = bbb+ccc*v-x
468 if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z):
469 return x
470
471 elif alpha == 1.0:
472 # expovariate(1)
473 u = random()
474 while u <= 1e-7:
475 u = random()
476 return -_log(u)
477
478 else: # alpha is between 0 and 1 (exclusive)
479
480 # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
481
482 while 1:
483 u = random()
484 b = (_e + alpha)/_e
485 p = b*u
486 if p <= 1.0:
487 x = pow(p, 1.0/alpha)
488 else:
489 # p > 1
490 x = -_log((b-p)/alpha)
491 u1 = random()
492 if not (((p <= 1.0) and (u1 > _exp(-x))) or
493 ((p > 1) and (u1 > pow(x, alpha - 1.0)))):
494 break
495 return x
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000496
Guido van Rossum95bfcda1994-03-09 14:21:05 +0000497
Tim Peterscd804102001-01-25 20:25:57 +0000498## -------------------- Gauss (faster alternative) --------------------
Guido van Rossum95bfcda1994-03-09 14:21:05 +0000499
Tim Petersd7b5e882001-01-25 03:36:26 +0000500 def gauss(self, mu, sigma):
Guido van Rossumcc32ac91994-03-15 16:10:24 +0000501
Tim Petersd7b5e882001-01-25 03:36:26 +0000502 # When x and y are two variables from [0, 1), uniformly
503 # distributed, then
504 #
505 # cos(2*pi*x)*sqrt(-2*log(1-y))
506 # sin(2*pi*x)*sqrt(-2*log(1-y))
507 #
508 # are two *independent* variables with normal distribution
509 # (mu = 0, sigma = 1).
510 # (Lambert Meertens)
511 # (corrected version; bug discovered by Mike Miller, fixed by LM)
Guido van Rossumcc32ac91994-03-15 16:10:24 +0000512
Tim Petersd7b5e882001-01-25 03:36:26 +0000513 # Multithreading note: When two threads call this function
514 # simultaneously, it is possible that they will receive the
515 # same return value. The window is very small though. To
516 # avoid this, you have to use a lock around all calls. (I
517 # didn't want to slow this down in the serial case by using a
518 # lock here.)
Guido van Rossumd03e1191998-05-29 17:51:31 +0000519
Tim Petersd7b5e882001-01-25 03:36:26 +0000520 random = self.random
521 z = self.gauss_next
522 self.gauss_next = None
523 if z is None:
524 x2pi = random() * TWOPI
525 g2rad = _sqrt(-2.0 * _log(1.0 - random()))
526 z = _cos(x2pi) * g2rad
527 self.gauss_next = _sin(x2pi) * g2rad
Guido van Rossumcc32ac91994-03-15 16:10:24 +0000528
Tim Petersd7b5e882001-01-25 03:36:26 +0000529 return mu + z*sigma
Guido van Rossum95bfcda1994-03-09 14:21:05 +0000530
Tim Peterscd804102001-01-25 20:25:57 +0000531## -------------------- beta --------------------
Tim Peters85e2e472001-01-26 06:49:56 +0000532## See
533## http://sourceforge.net/bugs/?func=detailbug&bug_id=130030&group_id=5470
534## for Ivan Frohne's insightful analysis of why the original implementation:
535##
536## def betavariate(self, alpha, beta):
537## # Discrete Event Simulation in C, pp 87-88.
538##
539## y = self.expovariate(alpha)
540## z = self.expovariate(1.0/beta)
541## return z/(y+z)
542##
543## was dead wrong, and how it probably got that way.
Guido van Rossum95bfcda1994-03-09 14:21:05 +0000544
Tim Petersd7b5e882001-01-25 03:36:26 +0000545 def betavariate(self, alpha, beta):
Tim Peters85e2e472001-01-26 06:49:56 +0000546 # This version due to Janne Sinkkonen, and matches all the std
547 # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution").
548 y = self.gammavariate(alpha, 1.)
549 if y == 0:
550 return 0.0
551 else:
552 return y / (y + self.gammavariate(beta, 1.))
Guido van Rossum95bfcda1994-03-09 14:21:05 +0000553
Tim Peterscd804102001-01-25 20:25:57 +0000554## -------------------- Pareto --------------------
Guido van Rossumcf4559a1997-12-02 02:47:39 +0000555
Tim Petersd7b5e882001-01-25 03:36:26 +0000556 def paretovariate(self, alpha):
557 # Jain, pg. 495
Guido van Rossumcf4559a1997-12-02 02:47:39 +0000558
Tim Petersd7b5e882001-01-25 03:36:26 +0000559 u = self.random()
560 return 1.0 / pow(u, 1.0/alpha)
Guido van Rossumcf4559a1997-12-02 02:47:39 +0000561
Tim Peterscd804102001-01-25 20:25:57 +0000562## -------------------- Weibull --------------------
Guido van Rossumcf4559a1997-12-02 02:47:39 +0000563
Tim Petersd7b5e882001-01-25 03:36:26 +0000564 def weibullvariate(self, alpha, beta):
565 # Jain, pg. 499; bug fix courtesy Bill Arms
Guido van Rossumcf4559a1997-12-02 02:47:39 +0000566
Tim Petersd7b5e882001-01-25 03:36:26 +0000567 u = self.random()
568 return alpha * pow(-_log(u), 1.0/beta)
Guido van Rossum6c395ba1999-08-18 13:53:28 +0000569
Tim Peterscd804102001-01-25 20:25:57 +0000570## -------------------- test program --------------------
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000571
Tim Petersd7b5e882001-01-25 03:36:26 +0000572def _test_generator(n, funccall):
Tim Peters0c9886d2001-01-15 01:18:21 +0000573 import time
574 print n, 'times', funccall
575 code = compile(funccall, funccall, 'eval')
576 sum = 0.0
577 sqsum = 0.0
578 smallest = 1e10
579 largest = -1e10
580 t0 = time.time()
581 for i in range(n):
582 x = eval(code)
583 sum = sum + x
584 sqsum = sqsum + x*x
585 smallest = min(x, smallest)
586 largest = max(x, largest)
587 t1 = time.time()
588 print round(t1-t0, 3), 'sec,',
589 avg = sum/n
Tim Petersd7b5e882001-01-25 03:36:26 +0000590 stddev = _sqrt(sqsum/n - avg*avg)
Tim Peters0c9886d2001-01-15 01:18:21 +0000591 print 'avg %g, stddev %g, min %g, max %g' % \
592 (avg, stddev, smallest, largest)
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000593
Tim Petersd7b5e882001-01-25 03:36:26 +0000594def _test(N=200):
595 print 'TWOPI =', TWOPI
596 print 'LOG4 =', LOG4
597 print 'NV_MAGICCONST =', NV_MAGICCONST
598 print 'SG_MAGICCONST =', SG_MAGICCONST
599 _test_generator(N, 'random()')
600 _test_generator(N, 'normalvariate(0.0, 1.0)')
601 _test_generator(N, 'lognormvariate(0.0, 1.0)')
602 _test_generator(N, 'cunifvariate(0.0, 1.0)')
603 _test_generator(N, 'expovariate(1.0)')
604 _test_generator(N, 'vonmisesvariate(0.0, 1.0)')
605 _test_generator(N, 'gammavariate(0.5, 1.0)')
606 _test_generator(N, 'gammavariate(0.9, 1.0)')
607 _test_generator(N, 'gammavariate(1.0, 1.0)')
608 _test_generator(N, 'gammavariate(2.0, 1.0)')
609 _test_generator(N, 'gammavariate(20.0, 1.0)')
610 _test_generator(N, 'gammavariate(200.0, 1.0)')
611 _test_generator(N, 'gauss(0.0, 1.0)')
612 _test_generator(N, 'betavariate(3.0, 3.0)')
613 _test_generator(N, 'paretovariate(1.0)')
614 _test_generator(N, 'weibullvariate(1.0, 1.0)')
615
Tim Peterscd804102001-01-25 20:25:57 +0000616 # Test jumpahead.
617 s = getstate()
618 jumpahead(N)
619 r1 = random()
620 # now do it the slow way
621 setstate(s)
622 for i in range(N):
623 random()
624 r2 = random()
625 if r1 != r2:
626 raise ValueError("jumpahead test failed " + `(N, r1, r2)`)
627
Tim Peters715c4c42001-01-26 22:56:56 +0000628# Create one instance, seeded from current time, and export its methods
629# as module-level functions. The functions are not threadsafe, and state
630# is shared across all uses (both in the user's code and in the Python
631# libraries), but that's fine for most programs and is easier for the
632# casual user than making them instantiate their own Random() instance.
Tim Petersd7b5e882001-01-25 03:36:26 +0000633_inst = Random()
634seed = _inst.seed
635random = _inst.random
636uniform = _inst.uniform
637randint = _inst.randint
638choice = _inst.choice
639randrange = _inst.randrange
640shuffle = _inst.shuffle
641normalvariate = _inst.normalvariate
642lognormvariate = _inst.lognormvariate
643cunifvariate = _inst.cunifvariate
644expovariate = _inst.expovariate
645vonmisesvariate = _inst.vonmisesvariate
646gammavariate = _inst.gammavariate
647stdgamma = _inst.stdgamma
648gauss = _inst.gauss
649betavariate = _inst.betavariate
650paretovariate = _inst.paretovariate
651weibullvariate = _inst.weibullvariate
652getstate = _inst.getstate
653setstate = _inst.setstate
Tim Petersd52269b2001-01-25 06:23:18 +0000654jumpahead = _inst.jumpahead
Tim Peters0de88fc2001-02-01 04:59:18 +0000655whseed = _inst.whseed
Tim Petersd7b5e882001-01-25 03:36:26 +0000656
Guido van Rossumff03b1a1994-03-09 12:55:02 +0000657if __name__ == '__main__':
Tim Petersd7b5e882001-01-25 03:36:26 +0000658 _test()