mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Minor code clean-ups (GH-20838) (GH-20858)
This commit is contained in:
		
							parent
							
								
									c932f5c1e5
								
							
						
					
					
						commit
						f1534d0840
					
				
					 1 changed files with 108 additions and 87 deletions
				
			
		
							
								
								
									
										195
									
								
								Lib/random.py
									
										
									
									
									
								
							
							
						
						
									
										195
									
								
								Lib/random.py
									
										
									
									
									
								
							|  | @ -39,7 +39,7 @@ | |||
| 
 | ||||
| from warnings import warn as _warn | ||||
| from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil | ||||
| from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin | ||||
| from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin, tau as TWOPI | ||||
| from os import urandom as _urandom | ||||
| from _collections_abc import Set as _Set, Sequence as _Sequence | ||||
| from itertools import accumulate as _accumulate, repeat as _repeat | ||||
|  | @ -54,19 +54,38 @@ | |||
|     from hashlib import sha512 as _sha512 | ||||
| 
 | ||||
| 
 | ||||
| __all__ = ["Random","seed","random","uniform","randint","choice","sample", | ||||
|            "randrange","shuffle","normalvariate","lognormvariate", | ||||
|            "expovariate","vonmisesvariate","gammavariate","triangular", | ||||
|            "gauss","betavariate","paretovariate","weibullvariate", | ||||
|            "getstate","setstate", "getrandbits", "choices", | ||||
|            "SystemRandom"] | ||||
| __all__ = [ | ||||
|     "Random", | ||||
|     "SystemRandom", | ||||
|     "betavariate", | ||||
|     "choice", | ||||
|     "choices", | ||||
|     "expovariate", | ||||
|     "gammavariate", | ||||
|     "gauss", | ||||
|     "getrandbits", | ||||
|     "getstate", | ||||
|     "lognormvariate", | ||||
|     "normalvariate", | ||||
|     "paretovariate", | ||||
|     "randint", | ||||
|     "random", | ||||
|     "randrange", | ||||
|     "sample", | ||||
|     "seed", | ||||
|     "setstate", | ||||
|     "shuffle", | ||||
|     "triangular", | ||||
|     "uniform", | ||||
|     "vonmisesvariate", | ||||
|     "weibullvariate", | ||||
| ] | ||||
| 
 | ||||
| NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0) | ||||
| TWOPI = 2.0*_pi | ||||
| NV_MAGICCONST = 4 * _exp(-0.5) / _sqrt(2.0) | ||||
| LOG4 = _log(4.0) | ||||
| SG_MAGICCONST = 1.0 + _log(4.5) | ||||
| BPF = 53        # Number of bits in a float | ||||
| RECIP_BPF = 2**-BPF | ||||
| RECIP_BPF = 2 ** -BPF | ||||
| 
 | ||||
| 
 | ||||
| # Translated by Guido van Rossum from C source provided by | ||||
|  | @ -75,6 +94,7 @@ | |||
| 
 | ||||
| import _random | ||||
| 
 | ||||
| 
 | ||||
| class Random(_random.Random): | ||||
|     """Random number generator base class used by bound module functions. | ||||
| 
 | ||||
|  | @ -180,7 +200,7 @@ def setstate(self, state): | |||
|             #   really unsigned 32-bit ints, so we convert negative ints from | ||||
|             #   version 2 to positive longs for version 3. | ||||
|             try: | ||||
|                 internalstate = tuple(x % (2**32) for x in internalstate) | ||||
|                 internalstate = tuple(x % (2 ** 32) for x in internalstate) | ||||
|             except ValueError as e: | ||||
|                 raise TypeError from e | ||||
|             super().setstate(internalstate) | ||||
|  | @ -189,21 +209,21 @@ def setstate(self, state): | |||
|                              "Random.setstate() of version %s" % | ||||
|                              (version, self.VERSION)) | ||||
| 
 | ||||
| ## ---- Methods below this point do not need to be overridden when | ||||
| ## ---- subclassing for the purpose of using a different core generator. | ||||
|     ## ---- Methods below this point do not need to be overridden when | ||||
|     ## ---- subclassing for the purpose of using a different core generator. | ||||
| 
 | ||||
| ## -------------------- bytes methods --------------------- | ||||
|     ## -------------------- bytes methods --------------------- | ||||
| 
 | ||||
|     def randbytes(self, n): | ||||
|         """Generate n random bytes.""" | ||||
|         return self.getrandbits(n * 8).to_bytes(n, 'little') | ||||
| 
 | ||||
| ## -------------------- pickle support  ------------------- | ||||
|     ## -------------------- pickle support  ------------------- | ||||
| 
 | ||||
|     # Issue 17489: Since __reduce__ was defined to fix #759889 this is no | ||||
|     # longer called; we leave it here because it has been here since random was | ||||
|     # rewritten back in 2001 and why risk breaking something. | ||||
|     def __getstate__(self): # for pickle | ||||
|     def __getstate__(self):  # for pickle | ||||
|         return self.getstate() | ||||
| 
 | ||||
|     def __setstate__(self, state):  # for pickle | ||||
|  | @ -212,7 +232,7 @@ def __setstate__(self, state):  # for pickle | |||
|     def __reduce__(self): | ||||
|         return self.__class__, (), self.getstate() | ||||
| 
 | ||||
| ## -------------------- integer methods  ------------------- | ||||
|     ## -------------------- integer methods  ------------------- | ||||
| 
 | ||||
|     def randrange(self, start, stop=None, step=1, _int=int): | ||||
|         """Choose a random item from range(start, stop[, step]). | ||||
|  | @ -256,7 +276,7 @@ def randrange(self, start, stop=None, step=1, _int=int): | |||
|         if n <= 0: | ||||
|             raise ValueError("empty range for randrange()") | ||||
| 
 | ||||
|         return istart + istep*self._randbelow(n) | ||||
|         return istart + istep * self._randbelow(n) | ||||
| 
 | ||||
|     def randint(self, a, b): | ||||
|         """Return random integer in range [a, b], including both end points. | ||||
|  | @ -271,7 +291,7 @@ def _randbelow_with_getrandbits(self, n): | |||
|             return 0 | ||||
|         getrandbits = self.getrandbits | ||||
|         k = n.bit_length()  # don't use (n-1) here because n can be 1 | ||||
|         r = getrandbits(k)          # 0 <= r < 2**k | ||||
|         r = getrandbits(k)  # 0 <= r < 2**k | ||||
|         while r >= n: | ||||
|             r = getrandbits(k) | ||||
|         return r | ||||
|  | @ -295,15 +315,16 @@ def _randbelow_without_getrandbits(self, n, int=int, maxsize=1<<BPF): | |||
|         r = random() | ||||
|         while r >= limit: | ||||
|             r = random() | ||||
|         return int(r*maxsize) % n | ||||
|         return int(r * maxsize) % n | ||||
| 
 | ||||
|     _randbelow = _randbelow_with_getrandbits | ||||
| 
 | ||||
| ## -------------------- sequence methods  ------------------- | ||||
|     ## -------------------- sequence methods  ------------------- | ||||
| 
 | ||||
|     def choice(self, seq): | ||||
|         """Choose a random element from a non-empty sequence.""" | ||||
|         return seq[self._randbelow(len(seq))] # raises IndexError if seq is empty | ||||
|         # raises IndexError if seq is empty | ||||
|         return seq[self._randbelow(len(seq))] | ||||
| 
 | ||||
|     def shuffle(self, x, random=None): | ||||
|         """Shuffle list x in place, and return None. | ||||
|  | @ -318,7 +339,7 @@ def shuffle(self, x, random=None): | |||
|             randbelow = self._randbelow | ||||
|             for i in reversed(range(1, len(x))): | ||||
|                 # pick an element in x[:i+1] with which to exchange x[i] | ||||
|                 j = randbelow(i+1) | ||||
|                 j = randbelow(i + 1) | ||||
|                 x[i], x[j] = x[j], x[i] | ||||
|         else: | ||||
|             _warn('The *random* parameter to shuffle() has been deprecated\n' | ||||
|  | @ -328,7 +349,7 @@ def shuffle(self, x, random=None): | |||
|             _int = int | ||||
|             for i in reversed(range(1, len(x))): | ||||
|                 # pick an element in x[:i+1] with which to exchange x[i] | ||||
|                 j = _int(random() * (i+1)) | ||||
|                 j = _int(random() * (i + 1)) | ||||
|                 x[i], x[j] = x[j], x[i] | ||||
| 
 | ||||
|     def sample(self, population, k, *, counts=None): | ||||
|  | @ -410,14 +431,15 @@ def sample(self, population, k, *, counts=None): | |||
|         result = [None] * k | ||||
|         setsize = 21        # size of a small set minus size of an empty list | ||||
|         if k > 5: | ||||
|             setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets | ||||
|             setsize += 4 ** _ceil(_log(k * 3, 4))  # table size for big sets | ||||
|         if n <= setsize: | ||||
|             # An n-length list is smaller than a k-length set | ||||
|             # An n-length list is smaller than a k-length set. | ||||
|             # Invariant:  non-selected at pool[0 : n-i] | ||||
|             pool = list(population) | ||||
|             for i in range(k):         # invariant:  non-selected at [0,n-i) | ||||
|                 j = randbelow(n-i) | ||||
|             for i in range(k): | ||||
|                 j = randbelow(n - i) | ||||
|                 result[i] = pool[j] | ||||
|                 pool[j] = pool[n-i-1]   # move non-selected item into vacancy | ||||
|                 pool[j] = pool[n - i - 1]  # move non-selected item into vacancy | ||||
|         else: | ||||
|             selected = set() | ||||
|             selected_add = selected.add | ||||
|  | @ -456,15 +478,15 @@ def choices(self, population, weights=None, *, cum_weights=None, k=1): | |||
|         return [population[bisect(cum_weights, random() * total, 0, hi)] | ||||
|                 for i in _repeat(None, k)] | ||||
| 
 | ||||
| ## -------------------- real-valued distributions  ------------------- | ||||
|     ## -------------------- real-valued distributions  ------------------- | ||||
| 
 | ||||
| ## -------------------- uniform distribution ------------------- | ||||
|     ## -------------------- uniform distribution ------------------- | ||||
| 
 | ||||
|     def uniform(self, a, b): | ||||
|         "Get a random number in the range [a, b) or [a, b] depending on rounding." | ||||
|         return a + (b-a) * self.random() | ||||
|         return a + (b - a) * self.random() | ||||
| 
 | ||||
| ## -------------------- triangular -------------------- | ||||
|     ## -------------------- triangular -------------------- | ||||
| 
 | ||||
|     def triangular(self, low=0.0, high=1.0, mode=None): | ||||
|         """Triangular distribution. | ||||
|  | @ -486,7 +508,7 @@ def triangular(self, low=0.0, high=1.0, mode=None): | |||
|             low, high = high, low | ||||
|         return low + (high - low) * _sqrt(u * c) | ||||
| 
 | ||||
| ## -------------------- normal distribution -------------------- | ||||
|     ## -------------------- normal distribution -------------------- | ||||
| 
 | ||||
|     def normalvariate(self, mu, sigma): | ||||
|         """Normal distribution. | ||||
|  | @ -502,16 +524,16 @@ def normalvariate(self, mu, sigma): | |||
|         # Math Software, 3, (1977), pp257-260. | ||||
| 
 | ||||
|         random = self.random | ||||
|         while 1: | ||||
|         while True: | ||||
|             u1 = random() | ||||
|             u2 = 1.0 - random() | ||||
|             z = NV_MAGICCONST*(u1-0.5)/u2 | ||||
|             zz = z*z/4.0 | ||||
|             z = NV_MAGICCONST * (u1 - 0.5) / u2 | ||||
|             zz = z * z / 4.0 | ||||
|             if zz <= -_log(u2): | ||||
|                 break | ||||
|         return mu + z*sigma | ||||
|         return mu + z * sigma | ||||
| 
 | ||||
| ## -------------------- lognormal distribution -------------------- | ||||
|     ## -------------------- lognormal distribution -------------------- | ||||
| 
 | ||||
|     def lognormvariate(self, mu, sigma): | ||||
|         """Log normal distribution. | ||||
|  | @ -523,7 +545,7 @@ def lognormvariate(self, mu, sigma): | |||
|         """ | ||||
|         return _exp(self.normalvariate(mu, sigma)) | ||||
| 
 | ||||
| ## -------------------- exponential distribution -------------------- | ||||
|     ## -------------------- exponential distribution -------------------- | ||||
| 
 | ||||
|     def expovariate(self, lambd): | ||||
|         """Exponential distribution. | ||||
|  | @ -540,9 +562,9 @@ def expovariate(self, lambd): | |||
| 
 | ||||
|         # we use 1-random() instead of random() to preclude the | ||||
|         # possibility of taking the log of zero. | ||||
|         return -_log(1.0 - self.random())/lambd | ||||
|         return -_log(1.0 - self.random()) / lambd | ||||
| 
 | ||||
| ## -------------------- von Mises distribution -------------------- | ||||
|     ## -------------------- von Mises distribution -------------------- | ||||
| 
 | ||||
|     def vonmisesvariate(self, mu, kappa): | ||||
|         """Circular data distribution. | ||||
|  | @ -571,7 +593,7 @@ def vonmisesvariate(self, mu, kappa): | |||
|         s = 0.5 / kappa | ||||
|         r = s + _sqrt(1.0 + s * s) | ||||
| 
 | ||||
|         while 1: | ||||
|         while True: | ||||
|             u1 = random() | ||||
|             z = _cos(_pi * u1) | ||||
| 
 | ||||
|  | @ -590,7 +612,7 @@ def vonmisesvariate(self, mu, kappa): | |||
| 
 | ||||
|         return theta | ||||
| 
 | ||||
| ## -------------------- gamma distribution -------------------- | ||||
|     ## -------------------- gamma distribution -------------------- | ||||
| 
 | ||||
|     def gammavariate(self, alpha, beta): | ||||
|         """Gamma distribution.  Not the gamma function! | ||||
|  | @ -625,32 +647,31 @@ def gammavariate(self, alpha, beta): | |||
| 
 | ||||
|             while 1: | ||||
|                 u1 = random() | ||||
|                 if not 1e-7 < u1 < .9999999: | ||||
|                 if not 1e-7 < u1 < 0.9999999: | ||||
|                     continue | ||||
|                 u2 = 1.0 - random() | ||||
|                 v = _log(u1/(1.0-u1))/ainv | ||||
|                 x = alpha*_exp(v) | ||||
|                 z = u1*u1*u2 | ||||
|                 r = bbb+ccc*v-x | ||||
|                 if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z): | ||||
|                 v = _log(u1 / (1.0 - u1)) / ainv | ||||
|                 x = alpha * _exp(v) | ||||
|                 z = u1 * u1 * u2 | ||||
|                 r = bbb + ccc * v - x | ||||
|                 if r + SG_MAGICCONST - 4.5 * z >= 0.0 or r >= _log(z): | ||||
|                     return x * beta | ||||
| 
 | ||||
|         elif alpha == 1.0: | ||||
|             # expovariate(1/beta) | ||||
|             return -_log(1.0 - random()) * beta | ||||
| 
 | ||||
|         else:   # alpha is between 0 and 1 (exclusive) | ||||
| 
 | ||||
|         else: | ||||
|             # alpha is between 0 and 1 (exclusive) | ||||
|             # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle | ||||
| 
 | ||||
|             while 1: | ||||
|             while True: | ||||
|                 u = random() | ||||
|                 b = (_e + alpha)/_e | ||||
|                 p = b*u | ||||
|                 b = (_e + alpha) / _e | ||||
|                 p = b * u | ||||
|                 if p <= 1.0: | ||||
|                     x = p ** (1.0/alpha) | ||||
|                     x = p ** (1.0 / alpha) | ||||
|                 else: | ||||
|                     x = -_log((b-p)/alpha) | ||||
|                     x = -_log((b - p) / alpha) | ||||
|                 u1 = random() | ||||
|                 if p > 1.0: | ||||
|                     if u1 <= x ** (alpha - 1.0): | ||||
|  | @ -659,7 +680,7 @@ def gammavariate(self, alpha, beta): | |||
|                     break | ||||
|             return x * beta | ||||
| 
 | ||||
| ## -------------------- Gauss (faster alternative) -------------------- | ||||
|     ## -------------------- Gauss (faster alternative) -------------------- | ||||
| 
 | ||||
|     def gauss(self, mu, sigma): | ||||
|         """Gaussian distribution. | ||||
|  | @ -698,21 +719,21 @@ def gauss(self, mu, sigma): | |||
|             z = _cos(x2pi) * g2rad | ||||
|             self.gauss_next = _sin(x2pi) * g2rad | ||||
| 
 | ||||
|         return mu + z*sigma | ||||
|         return mu + z * sigma | ||||
| 
 | ||||
| ## -------------------- beta -------------------- | ||||
| ## See | ||||
| ## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html | ||||
| ## for Ivan Frohne's insightful analysis of why the original implementation: | ||||
| ## | ||||
| ##    def betavariate(self, alpha, beta): | ||||
| ##        # Discrete Event Simulation in C, pp 87-88. | ||||
| ## | ||||
| ##        y = self.expovariate(alpha) | ||||
| ##        z = self.expovariate(1.0/beta) | ||||
| ##        return z/(y+z) | ||||
| ## | ||||
| ## was dead wrong, and how it probably got that way. | ||||
|     ## -------------------- beta -------------------- | ||||
|     ## See | ||||
|     ## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html | ||||
|     ## for Ivan Frohne's insightful analysis of why the original implementation: | ||||
|     ## | ||||
|     ##    def betavariate(self, alpha, beta): | ||||
|     ##        # Discrete Event Simulation in C, pp 87-88. | ||||
|     ## | ||||
|     ##        y = self.expovariate(alpha) | ||||
|     ##        z = self.expovariate(1.0/beta) | ||||
|     ##        return z/(y+z) | ||||
|     ## | ||||
|     ## was dead wrong, and how it probably got that way. | ||||
| 
 | ||||
|     def betavariate(self, alpha, beta): | ||||
|         """Beta distribution. | ||||
|  | @ -725,21 +746,20 @@ def betavariate(self, alpha, beta): | |||
|         # This version due to Janne Sinkkonen, and matches all the std | ||||
|         # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution"). | ||||
|         y = self.gammavariate(alpha, 1.0) | ||||
|         if y == 0: | ||||
|             return 0.0 | ||||
|         else: | ||||
|         if y: | ||||
|             return y / (y + self.gammavariate(beta, 1.0)) | ||||
|         return 0.0 | ||||
| 
 | ||||
| ## -------------------- Pareto -------------------- | ||||
|     ## -------------------- Pareto -------------------- | ||||
| 
 | ||||
|     def paretovariate(self, alpha): | ||||
|         """Pareto distribution.  alpha is the shape parameter.""" | ||||
|         # Jain, pg. 495 | ||||
| 
 | ||||
|         u = 1.0 - self.random() | ||||
|         return 1.0 / u ** (1.0/alpha) | ||||
|         return 1.0 / u ** (1.0 / alpha) | ||||
| 
 | ||||
| ## -------------------- Weibull -------------------- | ||||
|     ## -------------------- Weibull -------------------- | ||||
| 
 | ||||
|     def weibullvariate(self, alpha, beta): | ||||
|         """Weibull distribution. | ||||
|  | @ -750,7 +770,8 @@ def weibullvariate(self, alpha, beta): | |||
|         # Jain, pg. 499; bug fix courtesy Bill Arms | ||||
| 
 | ||||
|         u = 1.0 - self.random() | ||||
|         return alpha * (-_log(u)) ** (1.0/beta) | ||||
|         return alpha * (-_log(u)) ** (1.0 / beta) | ||||
| 
 | ||||
| 
 | ||||
| ## --------------- Operating System Random Source  ------------------ | ||||
| 
 | ||||
|  | @ -789,6 +810,7 @@ def _notimplemented(self, *args, **kwds): | |||
|         raise NotImplementedError('System entropy source does not have state.') | ||||
|     getstate = setstate = _notimplemented | ||||
| 
 | ||||
| 
 | ||||
| ## -------------------- test program -------------------- | ||||
| 
 | ||||
| def _test_generator(n, func, args): | ||||
|  | @ -806,11 +828,10 @@ def _test_generator(n, func, args): | |||
|         smallest = min(x, smallest) | ||||
|         largest = max(x, largest) | ||||
|     t1 = time.perf_counter() | ||||
|     print(round(t1-t0, 3), 'sec,', end=' ') | ||||
|     avg = total/n | ||||
|     stddev = _sqrt(sqsum/n - avg*avg) | ||||
|     print('avg %g, stddev %g, min %g, max %g\n' % \ | ||||
|               (avg, stddev, smallest, largest)) | ||||
|     print(round(t1 - t0, 3), 'sec,', end=' ') | ||||
|     avg = total / n | ||||
|     stddev = _sqrt(sqsum / n - avg * avg) | ||||
|     print('avg %g, stddev %g, min %g, max %g\n' % (avg, stddev, smallest, largest)) | ||||
| 
 | ||||
| 
 | ||||
| def _test(N=2000): | ||||
|  | @ -829,11 +850,11 @@ def _test(N=2000): | |||
|     _test_generator(N, gammavariate, (200.0, 1.0)) | ||||
|     _test_generator(N, gauss, (0.0, 1.0)) | ||||
|     _test_generator(N, betavariate, (3.0, 3.0)) | ||||
|     _test_generator(N, triangular, (0.0, 1.0, 1.0/3.0)) | ||||
|     _test_generator(N, triangular, (0.0, 1.0, 1.0 / 3.0)) | ||||
| 
 | ||||
| # Create one instance, seeded from current time, and export its methods | ||||
| # as module-level functions.  The functions share state across all uses | ||||
| #(both in the user's code and in the Python libraries), but that's fine | ||||
| # (both in the user's code and in the Python libraries), but that's fine | ||||
| # for most programs and is easier for the casual user than making them | ||||
| # instantiate their own Random() instance. | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)