1 """Random variable generators.
2
3 bytes
4 -----
5 uniform bytes (values between 0 and 255)
6
7 integers
8 --------
9 uniform within range
10
11 sequences
12 ---------
13 pick random element
14 pick random sample
15 pick weighted random sample
16 generate random permutation
17
18 distributions on the real line:
19 ------------------------------
20 uniform
21 triangular
22 normal (Gaussian)
23 lognormal
24 negative exponential
25 gamma
26 beta
27 pareto
28 Weibull
29
30 distributions on the circle (angles 0 to 2pi)
31 ---------------------------------------------
32 circular uniform
33 von Mises
34
35 General notes on the underlying Mersenne Twister core generator:
36
37 * The period is 2**19937-1.
38 * It is one of the most extensively tested generators in existence.
39 * The random() method is implemented in C, executes in a single Python step,
40 and is, therefore, threadsafe.
41
42 """
43
44 # Translated by Guido van Rossum from C source provided by
45 # Adrian Baddeley. Adapted by Raymond Hettinger for use with
46 # the Mersenne Twister and os.urandom() core generators.
47
48 from warnings import warn as _warn
49 from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil
50 from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
51 from math import tau as TWOPI, floor as _floor, isfinite as _isfinite
52 from os import urandom as _urandom
53 from _collections_abc import Set as _Set, Sequence as _Sequence
54 from operator import index as _index
55 from itertools import accumulate as _accumulate, repeat as _repeat
56 from bisect import bisect as _bisect
57 import os as _os
58 import _random
59
60 try:
61 # hashlib is pretty heavy to load, try lean internal module first
62 from _sha512 import sha512 as _sha512
63 except ImportError:
64 # fallback to official implementation
65 from hashlib import sha512 as _sha512
66
67 __all__ = [
68 "Random",
69 "SystemRandom",
70 "betavariate",
71 "choice",
72 "choices",
73 "expovariate",
74 "gammavariate",
75 "gauss",
76 "getrandbits",
77 "getstate",
78 "lognormvariate",
79 "normalvariate",
80 "paretovariate",
81 "randbytes",
82 "randint",
83 "random",
84 "randrange",
85 "sample",
86 "seed",
87 "setstate",
88 "shuffle",
89 "triangular",
90 "uniform",
91 "vonmisesvariate",
92 "weibullvariate",
93 ]
94
95 NV_MAGICCONST = 4 * _exp(-0.5) / _sqrt(2.0)
96 LOG4 = _log(4.0)
97 SG_MAGICCONST = 1.0 + _log(4.5)
98 BPF = 53 # Number of bits in a float
99 RECIP_BPF = 2 ** -BPF
100 _ONE = 1
101
102
103 class ESC[4;38;5;81mRandom(ESC[4;38;5;149m_randomESC[4;38;5;149m.ESC[4;38;5;149mRandom):
104 """Random number generator base class used by bound module functions.
105
106 Used to instantiate instances of Random to get generators that don't
107 share state.
108
109 Class Random can also be subclassed if you want to use a different basic
110 generator of your own devising: in that case, override the following
111 methods: random(), seed(), getstate(), and setstate().
112 Optionally, implement a getrandbits() method so that randrange()
113 can cover arbitrarily large ranges.
114
115 """
116
117 VERSION = 3 # used by getstate/setstate
118
119 def __init__(self, x=None):
120 """Initialize an instance.
121
122 Optional argument x controls seeding, as for Random.seed().
123 """
124
125 self.seed(x)
126 self.gauss_next = None
127
128 def seed(self, a=None, version=2):
129 """Initialize internal state from a seed.
130
131 The only supported seed types are None, int, float,
132 str, bytes, and bytearray.
133
134 None or no argument seeds from current time or from an operating
135 system specific randomness source if available.
136
137 If *a* is an int, all bits are used.
138
139 For version 2 (the default), all of the bits are used if *a* is a str,
140 bytes, or bytearray. For version 1 (provided for reproducing random
141 sequences from older versions of Python), the algorithm for str and
142 bytes generates a narrower range of seeds.
143
144 """
145
146 if version == 1 and isinstance(a, (str, bytes)):
147 a = a.decode('latin-1') if isinstance(a, bytes) else a
148 x = ord(a[0]) << 7 if a else 0
149 for c in map(ord, a):
150 x = ((1000003 * x) ^ c) & 0xFFFFFFFFFFFFFFFF
151 x ^= len(a)
152 a = -2 if x == -1 else x
153
154 elif version == 2 and isinstance(a, (str, bytes, bytearray)):
155 if isinstance(a, str):
156 a = a.encode()
157 a = int.from_bytes(a + _sha512(a).digest())
158
159 elif not isinstance(a, (type(None), int, float, str, bytes, bytearray)):
160 raise TypeError('The only supported seed types are: None,\n'
161 'int, float, str, bytes, and bytearray.')
162
163 super().seed(a)
164 self.gauss_next = None
165
166 def getstate(self):
167 """Return internal state; can be passed to setstate() later."""
168 return self.VERSION, super().getstate(), self.gauss_next
169
170 def setstate(self, state):
171 """Restore internal state from object returned by getstate()."""
172 version = state[0]
173 if version == 3:
174 version, internalstate, self.gauss_next = state
175 super().setstate(internalstate)
176 elif version == 2:
177 version, internalstate, self.gauss_next = state
178 # In version 2, the state was saved as signed ints, which causes
179 # inconsistencies between 32/64-bit systems. The state is
180 # really unsigned 32-bit ints, so we convert negative ints from
181 # version 2 to positive longs for version 3.
182 try:
183 internalstate = tuple(x % (2 ** 32) for x in internalstate)
184 except ValueError as e:
185 raise TypeError from e
186 super().setstate(internalstate)
187 else:
188 raise ValueError("state with version %s passed to "
189 "Random.setstate() of version %s" %
190 (version, self.VERSION))
191
192
193 ## -------------------------------------------------------
194 ## ---- Methods below this point do not need to be overridden or extended
195 ## ---- when subclassing for the purpose of using a different core generator.
196
197
198 ## -------------------- pickle support -------------------
199
200 # Issue 17489: Since __reduce__ was defined to fix #759889 this is no
201 # longer called; we leave it here because it has been here since random was
202 # rewritten back in 2001 and why risk breaking something.
203 def __getstate__(self): # for pickle
204 return self.getstate()
205
206 def __setstate__(self, state): # for pickle
207 self.setstate(state)
208
209 def __reduce__(self):
210 return self.__class__, (), self.getstate()
211
212
213 ## ---- internal support method for evenly distributed integers ----
214
215 def __init_subclass__(cls, /, **kwargs):
216 """Control how subclasses generate random integers.
217
218 The algorithm a subclass can use depends on the random() and/or
219 getrandbits() implementation available to it and determines
220 whether it can generate random integers from arbitrarily large
221 ranges.
222 """
223
224 for c in cls.__mro__:
225 if '_randbelow' in c.__dict__:
226 # just inherit it
227 break
228 if 'getrandbits' in c.__dict__:
229 cls._randbelow = cls._randbelow_with_getrandbits
230 break
231 if 'random' in c.__dict__:
232 cls._randbelow = cls._randbelow_without_getrandbits
233 break
234
235 def _randbelow_with_getrandbits(self, n):
236 "Return a random int in the range [0,n). Defined for n > 0."
237
238 getrandbits = self.getrandbits
239 k = n.bit_length() # don't use (n-1) here because n can be 1
240 r = getrandbits(k) # 0 <= r < 2**k
241 while r >= n:
242 r = getrandbits(k)
243 return r
244
245 def _randbelow_without_getrandbits(self, n, maxsize=1<<BPF):
246 """Return a random int in the range [0,n). Defined for n > 0.
247
248 The implementation does not use getrandbits, but only random.
249 """
250
251 random = self.random
252 if n >= maxsize:
253 _warn("Underlying random() generator does not supply \n"
254 "enough bits to choose from a population range this large.\n"
255 "To remove the range limitation, add a getrandbits() method.")
256 return _floor(random() * n)
257 rem = maxsize % n
258 limit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0
259 r = random()
260 while r >= limit:
261 r = random()
262 return _floor(r * maxsize) % n
263
264 _randbelow = _randbelow_with_getrandbits
265
266
267 ## --------------------------------------------------------
268 ## ---- Methods below this point generate custom distributions
269 ## ---- based on the methods defined above. They do not
270 ## ---- directly touch the underlying generator and only
271 ## ---- access randomness through the methods: random(),
272 ## ---- getrandbits(), or _randbelow().
273
274
275 ## -------------------- bytes methods ---------------------
276
277 def randbytes(self, n):
278 """Generate n random bytes."""
279 return self.getrandbits(n * 8).to_bytes(n, 'little')
280
281
282 ## -------------------- integer methods -------------------
283
284 def randrange(self, start, stop=None, step=_ONE):
285 """Choose a random item from range(stop) or range(start, stop[, step]).
286
287 Roughly equivalent to ``choice(range(start, stop, step))`` but
288 supports arbitrarily large ranges and is optimized for common cases.
289
290 """
291
292 # This code is a bit messy to make it fast for the
293 # common case while still doing adequate error checking.
294 try:
295 istart = _index(start)
296 except TypeError:
297 istart = int(start)
298 if istart != start:
299 _warn('randrange() will raise TypeError in the future',
300 DeprecationWarning, 2)
301 raise ValueError("non-integer arg 1 for randrange()")
302 _warn('non-integer arguments to randrange() have been deprecated '
303 'since Python 3.10 and will be removed in a subsequent '
304 'version',
305 DeprecationWarning, 2)
306 if stop is None:
307 # We don't check for "step != 1" because it hasn't been
308 # type checked and converted to an integer yet.
309 if step is not _ONE:
310 raise TypeError('Missing a non-None stop argument')
311 if istart > 0:
312 return self._randbelow(istart)
313 raise ValueError("empty range for randrange()")
314
315 # stop argument supplied.
316 try:
317 istop = _index(stop)
318 except TypeError:
319 istop = int(stop)
320 if istop != stop:
321 _warn('randrange() will raise TypeError in the future',
322 DeprecationWarning, 2)
323 raise ValueError("non-integer stop for randrange()")
324 _warn('non-integer arguments to randrange() have been deprecated '
325 'since Python 3.10 and will be removed in a subsequent '
326 'version',
327 DeprecationWarning, 2)
328 width = istop - istart
329 try:
330 istep = _index(step)
331 except TypeError:
332 istep = int(step)
333 if istep != step:
334 _warn('randrange() will raise TypeError in the future',
335 DeprecationWarning, 2)
336 raise ValueError("non-integer step for randrange()")
337 _warn('non-integer arguments to randrange() have been deprecated '
338 'since Python 3.10 and will be removed in a subsequent '
339 'version',
340 DeprecationWarning, 2)
341 # Fast path.
342 if istep == 1:
343 if width > 0:
344 return istart + self._randbelow(width)
345 raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
346
347 # Non-unit step argument supplied.
348 if istep > 0:
349 n = (width + istep - 1) // istep
350 elif istep < 0:
351 n = (width + istep + 1) // istep
352 else:
353 raise ValueError("zero step for randrange()")
354 if n <= 0:
355 raise ValueError("empty range for randrange()")
356 return istart + istep * self._randbelow(n)
357
358 def randint(self, a, b):
359 """Return random integer in range [a, b], including both end points.
360 """
361
362 return self.randrange(a, b+1)
363
364
365 ## -------------------- sequence methods -------------------
366
367 def choice(self, seq):
368 """Choose a random element from a non-empty sequence."""
369
370 # As an accommodation for NumPy, we don't use "if not seq"
371 # because bool(numpy.array()) raises a ValueError.
372 if not len(seq):
373 raise IndexError('Cannot choose from an empty sequence')
374 return seq[self._randbelow(len(seq))]
375
376 def shuffle(self, x):
377 """Shuffle list x in place, and return None."""
378
379 randbelow = self._randbelow
380 for i in reversed(range(1, len(x))):
381 # pick an element in x[:i+1] with which to exchange x[i]
382 j = randbelow(i + 1)
383 x[i], x[j] = x[j], x[i]
384
385 def sample(self, population, k, *, counts=None):
386 """Chooses k unique random elements from a population sequence.
387
388 Returns a new list containing elements from the population while
389 leaving the original population unchanged. The resulting list is
390 in selection order so that all sub-slices will also be valid random
391 samples. This allows raffle winners (the sample) to be partitioned
392 into grand prize and second place winners (the subslices).
393
394 Members of the population need not be hashable or unique. If the
395 population contains repeats, then each occurrence is a possible
396 selection in the sample.
397
398 Repeated elements can be specified one at a time or with the optional
399 counts parameter. For example:
400
401 sample(['red', 'blue'], counts=[4, 2], k=5)
402
403 is equivalent to:
404
405 sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)
406
407 To choose a sample from a range of integers, use range() for the
408 population argument. This is especially fast and space efficient
409 for sampling from a large population:
410
411 sample(range(10000000), 60)
412
413 """
414
415 # Sampling without replacement entails tracking either potential
416 # selections (the pool) in a list or previous selections in a set.
417
418 # When the number of selections is small compared to the
419 # population, then tracking selections is efficient, requiring
420 # only a small set and an occasional reselection. For
421 # a larger number of selections, the pool tracking method is
422 # preferred since the list takes less space than the
423 # set and it doesn't suffer from frequent reselections.
424
425 # The number of calls to _randbelow() is kept at or near k, the
426 # theoretical minimum. This is important because running time
427 # is dominated by _randbelow() and because it extracts the
428 # least entropy from the underlying random number generators.
429
430 # Memory requirements are kept to the smaller of a k-length
431 # set or an n-length list.
432
433 # There are other sampling algorithms that do not require
434 # auxiliary memory, but they were rejected because they made
435 # too many calls to _randbelow(), making them slower and
436 # causing them to eat more entropy than necessary.
437
438 if not isinstance(population, _Sequence):
439 raise TypeError("Population must be a sequence. "
440 "For dicts or sets, use sorted(d).")
441 n = len(population)
442 if counts is not None:
443 cum_counts = list(_accumulate(counts))
444 if len(cum_counts) != n:
445 raise ValueError('The number of counts does not match the population')
446 total = cum_counts.pop()
447 if not isinstance(total, int):
448 raise TypeError('Counts must be integers')
449 if total <= 0:
450 raise ValueError('Total of counts must be greater than zero')
451 selections = self.sample(range(total), k=k)
452 bisect = _bisect
453 return [population[bisect(cum_counts, s)] for s in selections]
454 randbelow = self._randbelow
455 if not 0 <= k <= n:
456 raise ValueError("Sample larger than population or is negative")
457 result = [None] * k
458 setsize = 21 # size of a small set minus size of an empty list
459 if k > 5:
460 setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets
461 if n <= setsize:
462 # An n-length list is smaller than a k-length set.
463 # Invariant: non-selected at pool[0 : n-i]
464 pool = list(population)
465 for i in range(k):
466 j = randbelow(n - i)
467 result[i] = pool[j]
468 pool[j] = pool[n - i - 1] # move non-selected item into vacancy
469 else:
470 selected = set()
471 selected_add = selected.add
472 for i in range(k):
473 j = randbelow(n)
474 while j in selected:
475 j = randbelow(n)
476 selected_add(j)
477 result[i] = population[j]
478 return result
479
480 def choices(self, population, weights=None, *, cum_weights=None, k=1):
481 """Return a k sized list of population elements chosen with replacement.
482
483 If the relative weights or cumulative weights are not specified,
484 the selections are made with equal probability.
485
486 """
487 random = self.random
488 n = len(population)
489 if cum_weights is None:
490 if weights is None:
491 floor = _floor
492 n += 0.0 # convert to float for a small speed improvement
493 return [population[floor(random() * n)] for i in _repeat(None, k)]
494 try:
495 cum_weights = list(_accumulate(weights))
496 except TypeError:
497 if not isinstance(weights, int):
498 raise
499 k = weights
500 raise TypeError(
501 f'The number of choices must be a keyword argument: {k=}'
502 ) from None
503 elif weights is not None:
504 raise TypeError('Cannot specify both weights and cumulative weights')
505 if len(cum_weights) != n:
506 raise ValueError('The number of weights does not match the population')
507 total = cum_weights[-1] + 0.0 # convert to float
508 if total <= 0.0:
509 raise ValueError('Total of weights must be greater than zero')
510 if not _isfinite(total):
511 raise ValueError('Total of weights must be finite')
512 bisect = _bisect
513 hi = n - 1
514 return [population[bisect(cum_weights, random() * total, 0, hi)]
515 for i in _repeat(None, k)]
516
517
518 ## -------------------- real-valued distributions -------------------
519
520 def uniform(self, a, b):
521 "Get a random number in the range [a, b) or [a, b] depending on rounding."
522 return a + (b - a) * self.random()
523
524 def triangular(self, low=0.0, high=1.0, mode=None):
525 """Triangular distribution.
526
527 Continuous distribution bounded by given lower and upper limits,
528 and having a given mode value in-between.
529
530 http://en.wikipedia.org/wiki/Triangular_distribution
531
532 """
533 u = self.random()
534 try:
535 c = 0.5 if mode is None else (mode - low) / (high - low)
536 except ZeroDivisionError:
537 return low
538 if u > c:
539 u = 1.0 - u
540 c = 1.0 - c
541 low, high = high, low
542 return low + (high - low) * _sqrt(u * c)
543
544 def normalvariate(self, mu=0.0, sigma=1.0):
545 """Normal distribution.
546
547 mu is the mean, and sigma is the standard deviation.
548
549 """
550 # Uses Kinderman and Monahan method. Reference: Kinderman,
551 # A.J. and Monahan, J.F., "Computer generation of random
552 # variables using the ratio of uniform deviates", ACM Trans
553 # Math Software, 3, (1977), pp257-260.
554
555 random = self.random
556 while True:
557 u1 = random()
558 u2 = 1.0 - random()
559 z = NV_MAGICCONST * (u1 - 0.5) / u2
560 zz = z * z / 4.0
561 if zz <= -_log(u2):
562 break
563 return mu + z * sigma
564
565 def gauss(self, mu=0.0, sigma=1.0):
566 """Gaussian distribution.
567
568 mu is the mean, and sigma is the standard deviation. This is
569 slightly faster than the normalvariate() function.
570
571 Not thread-safe without a lock around calls.
572
573 """
574 # When x and y are two variables from [0, 1), uniformly
575 # distributed, then
576 #
577 # cos(2*pi*x)*sqrt(-2*log(1-y))
578 # sin(2*pi*x)*sqrt(-2*log(1-y))
579 #
580 # are two *independent* variables with normal distribution
581 # (mu = 0, sigma = 1).
582 # (Lambert Meertens)
583 # (corrected version; bug discovered by Mike Miller, fixed by LM)
584
585 # Multithreading note: When two threads call this function
586 # simultaneously, it is possible that they will receive the
587 # same return value. The window is very small though. To
588 # avoid this, you have to use a lock around all calls. (I
589 # didn't want to slow this down in the serial case by using a
590 # lock here.)
591
592 random = self.random
593 z = self.gauss_next
594 self.gauss_next = None
595 if z is None:
596 x2pi = random() * TWOPI
597 g2rad = _sqrt(-2.0 * _log(1.0 - random()))
598 z = _cos(x2pi) * g2rad
599 self.gauss_next = _sin(x2pi) * g2rad
600
601 return mu + z * sigma
602
603 def lognormvariate(self, mu, sigma):
604 """Log normal distribution.
605
606 If you take the natural logarithm of this distribution, you'll get a
607 normal distribution with mean mu and standard deviation sigma.
608 mu can have any value, and sigma must be greater than zero.
609
610 """
611 return _exp(self.normalvariate(mu, sigma))
612
613 def expovariate(self, lambd):
614 """Exponential distribution.
615
616 lambd is 1.0 divided by the desired mean. It should be
617 nonzero. (The parameter would be called "lambda", but that is
618 a reserved word in Python.) Returned values range from 0 to
619 positive infinity if lambd is positive, and from negative
620 infinity to 0 if lambd is negative.
621
622 """
623 # lambd: rate lambd = 1/mean
624 # ('lambda' is a Python reserved word)
625
626 # we use 1-random() instead of random() to preclude the
627 # possibility of taking the log of zero.
628 return -_log(1.0 - self.random()) / lambd
629
630 def vonmisesvariate(self, mu, kappa):
631 """Circular data distribution.
632
633 mu is the mean angle, expressed in radians between 0 and 2*pi, and
634 kappa is the concentration parameter, which must be greater than or
635 equal to zero. If kappa is equal to zero, this distribution reduces
636 to a uniform random angle over the range 0 to 2*pi.
637
638 """
639 # Based upon an algorithm published in: Fisher, N.I.,
640 # "Statistical Analysis of Circular Data", Cambridge
641 # University Press, 1993.
642
643 # Thanks to Magnus Kessler for a correction to the
644 # implementation of step 4.
645
646 random = self.random
647 if kappa <= 1e-6:
648 return TWOPI * random()
649
650 s = 0.5 / kappa
651 r = s + _sqrt(1.0 + s * s)
652
653 while True:
654 u1 = random()
655 z = _cos(_pi * u1)
656
657 d = z / (r + z)
658 u2 = random()
659 if u2 < 1.0 - d * d or u2 <= (1.0 - d) * _exp(d):
660 break
661
662 q = 1.0 / r
663 f = (q + z) / (1.0 + q * z)
664 u3 = random()
665 if u3 > 0.5:
666 theta = (mu + _acos(f)) % TWOPI
667 else:
668 theta = (mu - _acos(f)) % TWOPI
669
670 return theta
671
672 def gammavariate(self, alpha, beta):
673 """Gamma distribution. Not the gamma function!
674
675 Conditions on the parameters are alpha > 0 and beta > 0.
676
677 The probability distribution function is:
678
679 x ** (alpha - 1) * math.exp(-x / beta)
680 pdf(x) = --------------------------------------
681 math.gamma(alpha) * beta ** alpha
682
683 """
684 # alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2
685
686 # Warning: a few older sources define the gamma distribution in terms
687 # of alpha > -1.0
688 if alpha <= 0.0 or beta <= 0.0:
689 raise ValueError('gammavariate: alpha and beta must be > 0.0')
690
691 random = self.random
692 if alpha > 1.0:
693
694 # Uses R.C.H. Cheng, "The generation of Gamma
695 # variables with non-integral shape parameters",
696 # Applied Statistics, (1977), 26, No. 1, p71-74
697
698 ainv = _sqrt(2.0 * alpha - 1.0)
699 bbb = alpha - LOG4
700 ccc = alpha + ainv
701
702 while True:
703 u1 = random()
704 if not 1e-7 < u1 < 0.9999999:
705 continue
706 u2 = 1.0 - random()
707 v = _log(u1 / (1.0 - u1)) / ainv
708 x = alpha * _exp(v)
709 z = u1 * u1 * u2
710 r = bbb + ccc * v - x
711 if r + SG_MAGICCONST - 4.5 * z >= 0.0 or r >= _log(z):
712 return x * beta
713
714 elif alpha == 1.0:
715 # expovariate(1/beta)
716 return -_log(1.0 - random()) * beta
717
718 else:
719 # alpha is between 0 and 1 (exclusive)
720 # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
721 while True:
722 u = random()
723 b = (_e + alpha) / _e
724 p = b * u
725 if p <= 1.0:
726 x = p ** (1.0 / alpha)
727 else:
728 x = -_log((b - p) / alpha)
729 u1 = random()
730 if p > 1.0:
731 if u1 <= x ** (alpha - 1.0):
732 break
733 elif u1 <= _exp(-x):
734 break
735 return x * beta
736
737 def betavariate(self, alpha, beta):
738 """Beta distribution.
739
740 Conditions on the parameters are alpha > 0 and beta > 0.
741 Returned values range between 0 and 1.
742
743 """
744 ## See
745 ## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html
746 ## for Ivan Frohne's insightful analysis of why the original implementation:
747 ##
748 ## def betavariate(self, alpha, beta):
749 ## # Discrete Event Simulation in C, pp 87-88.
750 ##
751 ## y = self.expovariate(alpha)
752 ## z = self.expovariate(1.0/beta)
753 ## return z/(y+z)
754 ##
755 ## was dead wrong, and how it probably got that way.
756
757 # This version due to Janne Sinkkonen, and matches all the std
758 # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution").
759 y = self.gammavariate(alpha, 1.0)
760 if y:
761 return y / (y + self.gammavariate(beta, 1.0))
762 return 0.0
763
764 def paretovariate(self, alpha):
765 """Pareto distribution. alpha is the shape parameter."""
766 # Jain, pg. 495
767
768 u = 1.0 - self.random()
769 return u ** (-1.0 / alpha)
770
771 def weibullvariate(self, alpha, beta):
772 """Weibull distribution.
773
774 alpha is the scale parameter and beta is the shape parameter.
775
776 """
777 # Jain, pg. 499; bug fix courtesy Bill Arms
778
779 u = 1.0 - self.random()
780 return alpha * (-_log(u)) ** (1.0 / beta)
781
782
783 ## ------------------------------------------------------------------
784 ## --------------- Operating System Random Source ------------------
785
786
787 class ESC[4;38;5;81mSystemRandom(ESC[4;38;5;149mRandom):
788 """Alternate random number generator using sources provided
789 by the operating system (such as /dev/urandom on Unix or
790 CryptGenRandom on Windows).
791
792 Not available on all systems (see os.urandom() for details).
793
794 """
795
796 def random(self):
797 """Get the next random number in the range 0.0 <= X < 1.0."""
798 return (int.from_bytes(_urandom(7)) >> 3) * RECIP_BPF
799
800 def getrandbits(self, k):
801 """getrandbits(k) -> x. Generates an int with k random bits."""
802 if k < 0:
803 raise ValueError('number of bits must be non-negative')
804 numbytes = (k + 7) // 8 # bits / 8 and rounded up
805 x = int.from_bytes(_urandom(numbytes))
806 return x >> (numbytes * 8 - k) # trim excess bits
807
808 def randbytes(self, n):
809 """Generate n random bytes."""
810 # os.urandom(n) fails with ValueError for n < 0
811 # and returns an empty bytes string for n == 0.
812 return _urandom(n)
813
814 def seed(self, *args, **kwds):
815 "Stub method. Not used for a system random number generator."
816 return None
817
818 def _notimplemented(self, *args, **kwds):
819 "Method should not be called for a system random number generator."
820 raise NotImplementedError('System entropy source does not have state.')
821 getstate = setstate = _notimplemented
822
823
824 # ----------------------------------------------------------------------
825 # Create one instance, seeded from current time, and export its methods
826 # as module-level functions. The functions share state across all uses
827 # (both in the user's code and in the Python libraries), but that's fine
828 # for most programs and is easier for the casual user than making them
829 # instantiate their own Random() instance.
830
831 _inst = Random()
832 seed = _inst.seed
833 random = _inst.random
834 uniform = _inst.uniform
835 triangular = _inst.triangular
836 randint = _inst.randint
837 choice = _inst.choice
838 randrange = _inst.randrange
839 sample = _inst.sample
840 shuffle = _inst.shuffle
841 choices = _inst.choices
842 normalvariate = _inst.normalvariate
843 lognormvariate = _inst.lognormvariate
844 expovariate = _inst.expovariate
845 vonmisesvariate = _inst.vonmisesvariate
846 gammavariate = _inst.gammavariate
847 gauss = _inst.gauss
848 betavariate = _inst.betavariate
849 paretovariate = _inst.paretovariate
850 weibullvariate = _inst.weibullvariate
851 getstate = _inst.getstate
852 setstate = _inst.setstate
853 getrandbits = _inst.getrandbits
854 randbytes = _inst.randbytes
855
856
857 ## ------------------------------------------------------
858 ## ----------------- test program -----------------------
859
860 def _test_generator(n, func, args):
861 from statistics import stdev, fmean as mean
862 from time import perf_counter
863
864 t0 = perf_counter()
865 data = [func(*args) for i in _repeat(None, n)]
866 t1 = perf_counter()
867
868 xbar = mean(data)
869 sigma = stdev(data, xbar)
870 low = min(data)
871 high = max(data)
872
873 print(f'{t1 - t0:.3f} sec, {n} times {func.__name__}')
874 print('avg %g, stddev %g, min %g, max %g\n' % (xbar, sigma, low, high))
875
876
877 def _test(N=2000):
878 _test_generator(N, random, ())
879 _test_generator(N, normalvariate, (0.0, 1.0))
880 _test_generator(N, lognormvariate, (0.0, 1.0))
881 _test_generator(N, vonmisesvariate, (0.0, 1.0))
882 _test_generator(N, gammavariate, (0.01, 1.0))
883 _test_generator(N, gammavariate, (0.1, 1.0))
884 _test_generator(N, gammavariate, (0.1, 2.0))
885 _test_generator(N, gammavariate, (0.5, 1.0))
886 _test_generator(N, gammavariate, (0.9, 1.0))
887 _test_generator(N, gammavariate, (1.0, 1.0))
888 _test_generator(N, gammavariate, (2.0, 1.0))
889 _test_generator(N, gammavariate, (20.0, 1.0))
890 _test_generator(N, gammavariate, (200.0, 1.0))
891 _test_generator(N, gauss, (0.0, 1.0))
892 _test_generator(N, betavariate, (3.0, 3.0))
893 _test_generator(N, triangular, (0.0, 1.0, 1.0 / 3.0))
894
895
896 ## ------------------------------------------------------
897 ## ------------------ fork support ---------------------
898
899 if hasattr(_os, "fork"):
900 _os.register_at_fork(after_in_child=_inst.seed)
901
902
903 if __name__ == '__main__':
904 _test()