同步操作将从 OpenHarmony-SIG/python 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
"""Random variable generators.integers--------uniform within rangesequences---------pick random elementpick random samplepick weighted random samplegenerate random permutationdistributions on the real line:------------------------------uniformtriangularnormal (Gaussian)lognormalnegative exponentialgammabetaparetoWeibulldistributions on the circle (angles 0 to 2pi)---------------------------------------------circular uniformvon MisesGeneral notes on the underlying Mersenne Twister core generator:* The period is 2**19937-1.* It is one of the most extensively tested generators in existence.* The random() method is implemented in C, executes in a single Python step,and is, therefore, threadsafe."""from warnings import warn as _warnfrom math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceilfrom math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sinfrom os import urandom as _urandomfrom _collections_abc import Set as _Set, Sequence as _Sequencefrom itertools import accumulate as _accumulate, repeat as _repeatfrom bisect import bisect as _bisectimport os as _ostry:# hashlib is pretty heavy to load, try lean internal module firstfrom _sha512 import sha512 as _sha512except ImportError:# fallback to official implementationfrom 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"]NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)TWOPI = 2.0*_piLOG4 = _log(4.0)SG_MAGICCONST = 1.0 + _log(4.5)BPF = 53 # Number of bits in a floatRECIP_BPF = 2**-BPF# Translated by Guido van Rossum from C source provided by# Adrian Baddeley. Adapted by Raymond Hettinger for use with# the Mersenne Twister and os.urandom() core generators.import _randomclass Random(_random.Random):"""Random number generator base class used by bound module functions.Used to instantiate instances of Random to get generators that don'tshare state.Class Random can also be subclassed if you want to use a different basicgenerator of your own devising: in that case, override the followingmethods: random(), seed(), getstate(), and setstate().Optionally, implement a getrandbits() method so that randrange()can cover arbitrarily large ranges."""VERSION = 3 # used by getstate/setstatedef __init__(self, x=None):"""Initialize an instance.Optional argument x controls seeding, as for Random.seed()."""self.seed(x)self.gauss_next = Nonedef __init_subclass__(cls, /, **kwargs):"""Control how subclasses generate random integers.The algorithm a subclass can use depends on the random() and/orgetrandbits() implementation available to it and determineswhether it can generate random integers from arbitrarily largeranges."""for c in cls.__mro__:if '_randbelow' in c.__dict__:# just inherit itbreakif 'getrandbits' in c.__dict__:cls._randbelow = cls._randbelow_with_getrandbitsbreakif 'random' in c.__dict__:cls._randbelow = cls._randbelow_without_getrandbitsbreakdef seed(self, a=None, version=2):"""Initialize internal state from hashable object.None or no argument seeds from current time or from an operatingsystem specific randomness source if available.If *a* is an int, all bits are used.For version 2 (the default), all of the bits are used if *a* is a str,bytes, or bytearray. For version 1 (provided for reproducing randomsequences from older versions of Python), the algorithm for str andbytes generates a narrower range of seeds."""if version == 1 and isinstance(a, (str, bytes)):a = a.decode('latin-1') if isinstance(a, bytes) else ax = ord(a[0]) << 7 if a else 0for c in map(ord, a):x = ((1000003 * x) ^ c) & 0xFFFFFFFFFFFFFFFFx ^= len(a)a = -2 if x == -1 else xif version == 2 and isinstance(a, (str, bytes, bytearray)):if isinstance(a, str):a = a.encode()a += _sha512(a).digest()a = int.from_bytes(a, 'big')super().seed(a)self.gauss_next = Nonedef getstate(self):"""Return internal state; can be passed to setstate() later."""return self.VERSION, super().getstate(), self.gauss_nextdef setstate(self, state):"""Restore internal state from object returned by getstate()."""version = state[0]if version == 3:version, internalstate, self.gauss_next = statesuper().setstate(internalstate)elif version == 2:version, internalstate, self.gauss_next = state# In version 2, the state was saved as signed ints, which causes# inconsistencies between 32/64-bit systems. The state is# 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)except ValueError as e:raise TypeError from esuper().setstate(internalstate)else:raise ValueError("state with version %s passed to ""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.## -------------------- 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 picklereturn self.getstate()def __setstate__(self, state): # for pickleself.setstate(state)def __reduce__(self):return self.__class__, (), self.getstate()## -------------------- integer methods -------------------def randrange(self, start, stop=None, step=1, _int=int):"""Choose a random item from range(start, stop[, step]).This fixes the problem with randint() which includes theendpoint; in Python this is usually not what you want."""# This code is a bit messy to make it fast for the# common case while still doing adequate error checking.istart = _int(start)if istart != start:raise ValueError("non-integer arg 1 for randrange()")if stop is None:if istart > 0:return self._randbelow(istart)raise ValueError("empty range for randrange()")# stop argument supplied.istop = _int(stop)if istop != stop:raise ValueError("non-integer stop for randrange()")width = istop - istartif step == 1 and width > 0:return istart + self._randbelow(width)if step == 1:raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))# Non-unit step argument supplied.istep = _int(step)if istep != step:raise ValueError("non-integer step for randrange()")if istep > 0:n = (width + istep - 1) // istepelif istep < 0:n = (width + istep + 1) // istepelse:raise ValueError("zero step for randrange()")if n <= 0:raise ValueError("empty range for randrange()")return istart + istep*self._randbelow(n)def randint(self, a, b):"""Return random integer in range [a, b], including both end points."""return self.randrange(a, b+1)def _randbelow_with_getrandbits(self, n):"Return a random int in the range [0,n). Raises ValueError if n==0."getrandbits = self.getrandbitsk = n.bit_length() # don't use (n-1) here because n can be 1r = getrandbits(k) # 0 <= r < 2**kwhile r >= n:r = getrandbits(k)return rdef _randbelow_without_getrandbits(self, n, int=int, maxsize=1<<BPF):"""Return a random int in the range [0,n). Raises ValueError if n==0.The implementation does not use getrandbits, but only random."""random = self.randomif n >= maxsize:_warn("Underlying random() generator does not supply \n""enough bits to choose from a population range this large.\n""To remove the range limitation, add a getrandbits() method.")return int(random() * n)if n == 0:raise ValueError("Boundary cannot be zero")rem = maxsize % nlimit = (maxsize - rem) / maxsize # int(limit * maxsize) % n == 0r = random()while r >= limit:r = random()return int(r*maxsize) % n_randbelow = _randbelow_with_getrandbits## -------------------- sequence methods -------------------def choice(self, seq):"""Choose a random element from a non-empty sequence."""try:i = self._randbelow(len(seq))except ValueError:raise IndexError('Cannot choose from an empty sequence') from Nonereturn seq[i]def shuffle(self, x, random=None):"""Shuffle list x in place, and return None.Optional argument random is a 0-argument function returning arandom float in [0.0, 1.0); if it is the default None, thestandard random.random will be used."""if random is None:randbelow = self._randbelowfor i in reversed(range(1, len(x))):# pick an element in x[:i+1] with which to exchange x[i]j = randbelow(i+1)x[i], x[j] = x[j], x[i]else:_int = intfor 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))x[i], x[j] = x[j], x[i]def sample(self, population, k):"""Chooses k unique random elements from a population sequence or set.Returns a new list containing elements from the population whileleaving the original population unchanged. The resulting list isin selection order so that all sub-slices will also be valid randomsamples. This allows raffle winners (the sample) to be partitionedinto grand prize and second place winners (the subslices).Members of the population need not be hashable or unique. If thepopulation contains repeats, then each occurrence is a possibleselection in the sample.To choose a sample in a range of integers, use range as an argument.This is especially fast and space efficient for sampling from alarge population: sample(range(10000000), 60)"""# Sampling without replacement entails tracking either potential# selections (the pool) in a list or previous selections in a set.# When the number of selections is small compared to the# population, then tracking selections is efficient, requiring# only a small set and an occasional reselection. For# a larger number of selections, the pool tracking method is# preferred since the list takes less space than the# set and it doesn't suffer from frequent reselections.# The number of calls to _randbelow() is kept at or near k, the# theoretical minimum. This is important because running time# is dominated by _randbelow() and because it extracts the# least entropy from the underlying random number generators.# Memory requirements are kept to the smaller of a k-length# set or an n-length list.# There are other sampling algorithms that do not require# auxiliary memory, but they were rejected because they made# too many calls to _randbelow(), making them slower and# causing them to eat more entropy than necessary.if isinstance(population, _Set):population = tuple(population)if not isinstance(population, _Sequence):raise TypeError("Population must be a sequence or set. For dicts, use list(d).")randbelow = self._randbelown = len(population)if not 0 <= k <= n:raise ValueError("Sample larger than population or is negative")result = [None] * ksetsize = 21 # size of a small set minus size of an empty listif k > 5:setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big setsif n <= setsize:# An n-length list is smaller than a k-length setpool = list(population)for i in range(k): # invariant: non-selected at [0,n-i)j = randbelow(n-i)result[i] = pool[j]pool[j] = pool[n-i-1] # move non-selected item into vacancyelse:selected = set()selected_add = selected.addfor i in range(k):j = randbelow(n)while j in selected:j = randbelow(n)selected_add(j)result[i] = population[j]return resultdef choices(self, population, weights=None, *, cum_weights=None, k=1):"""Return a k sized list of population elements chosen with replacement.If the relative weights or cumulative weights are not specified,the selections are made with equal probability."""random = self.randomn = len(population)if cum_weights is None:if weights is None:_int = intn += 0.0 # convert to float for a small speed improvementreturn [population[_int(random() * n)] for i in _repeat(None, k)]cum_weights = list(_accumulate(weights))elif weights is not None:raise TypeError('Cannot specify both weights and cumulative weights')if len(cum_weights) != n:raise ValueError('The number of weights does not match the population')bisect = _bisecttotal = cum_weights[-1] + 0.0 # convert to floathi = n - 1return [population[bisect(cum_weights, random() * total, 0, hi)]for i in _repeat(None, k)]## -------------------- real-valued distributions -------------------## -------------------- 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()## -------------------- triangular --------------------def triangular(self, low=0.0, high=1.0, mode=None):"""Triangular distribution.Continuous distribution bounded by given lower and upper limits,and having a given mode value in-between.http://en.wikipedia.org/wiki/Triangular_distribution"""u = self.random()try:c = 0.5 if mode is None else (mode - low) / (high - low)except ZeroDivisionError:return lowif u > c:u = 1.0 - uc = 1.0 - clow, high = high, lowreturn low + (high - low) * _sqrt(u * c)## -------------------- normal distribution --------------------def normalvariate(self, mu, sigma):"""Normal distribution.mu is the mean, and sigma is the standard deviation."""# mu = mean, sigma = standard deviation# Uses Kinderman and Monahan method. Reference: Kinderman,# A.J. and Monahan, J.F., "Computer generation of random# variables using the ratio of uniform deviates", ACM Trans# Math Software, 3, (1977), pp257-260.random = self.randomwhile 1:u1 = random()u2 = 1.0 - random()z = NV_MAGICCONST*(u1-0.5)/u2zz = z*z/4.0if zz <= -_log(u2):breakreturn mu + z*sigma## -------------------- lognormal distribution --------------------def lognormvariate(self, mu, sigma):"""Log normal distribution.If you take the natural logarithm of this distribution, you'll get anormal distribution with mean mu and standard deviation sigma.mu can have any value, and sigma must be greater than zero."""return _exp(self.normalvariate(mu, sigma))## -------------------- exponential distribution --------------------def expovariate(self, lambd):"""Exponential distribution.lambd is 1.0 divided by the desired mean. It should benonzero. (The parameter would be called "lambda", but that isa reserved word in Python.) Returned values range from 0 topositive infinity if lambd is positive, and from negativeinfinity to 0 if lambd is negative."""# lambd: rate lambd = 1/mean# ('lambda' is a Python reserved word)# we use 1-random() instead of random() to preclude the# possibility of taking the log of zero.return -_log(1.0 - self.random())/lambd## -------------------- von Mises distribution --------------------def vonmisesvariate(self, mu, kappa):"""Circular data distribution.mu is the mean angle, expressed in radians between 0 and 2*pi, andkappa is the concentration parameter, which must be greater than orequal to zero. If kappa is equal to zero, this distribution reducesto a uniform random angle over the range 0 to 2*pi."""# mu: mean angle (in radians between 0 and 2*pi)# kappa: concentration parameter kappa (>= 0)# if kappa = 0 generate uniform random angle# Based upon an algorithm published in: Fisher, N.I.,# "Statistical Analysis of Circular Data", Cambridge# University Press, 1993.# Thanks to Magnus Kessler for a correction to the# implementation of step 4.random = self.randomif kappa <= 1e-6:return TWOPI * random()s = 0.5 / kappar = s + _sqrt(1.0 + s * s)while 1:u1 = random()z = _cos(_pi * u1)d = z / (r + z)u2 = random()if u2 < 1.0 - d * d or u2 <= (1.0 - d) * _exp(d):breakq = 1.0 / rf = (q + z) / (1.0 + q * z)u3 = random()if u3 > 0.5:theta = (mu + _acos(f)) % TWOPIelse:theta = (mu - _acos(f)) % TWOPIreturn theta## -------------------- gamma distribution --------------------def gammavariate(self, alpha, beta):"""Gamma distribution. Not the gamma function!Conditions on the parameters are alpha > 0 and beta > 0.The probability distribution function is:x ** (alpha - 1) * math.exp(-x / beta)pdf(x) = --------------------------------------math.gamma(alpha) * beta ** alpha"""# alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2# Warning: a few older sources define the gamma distribution in terms# of alpha > -1.0if alpha <= 0.0 or beta <= 0.0:raise ValueError('gammavariate: alpha and beta must be > 0.0')random = self.randomif alpha > 1.0:# Uses R.C.H. Cheng, "The generation of Gamma# variables with non-integral shape parameters",# Applied Statistics, (1977), 26, No. 1, p71-74ainv = _sqrt(2.0 * alpha - 1.0)bbb = alpha - LOG4ccc = alpha + ainvwhile 1:u1 = random()if not 1e-7 < u1 < .9999999:continueu2 = 1.0 - random()v = _log(u1/(1.0-u1))/ainvx = alpha*_exp(v)z = u1*u1*u2r = bbb+ccc*v-xif r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z):return x * betaelif alpha == 1.0:# expovariate(1/beta)return -_log(1.0 - random()) * betaelse: # alpha is between 0 and 1 (exclusive)# Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentlewhile 1:u = random()b = (_e + alpha)/_ep = b*uif p <= 1.0:x = p ** (1.0/alpha)else:x = -_log((b-p)/alpha)u1 = random()if p > 1.0:if u1 <= x ** (alpha - 1.0):breakelif u1 <= _exp(-x):breakreturn x * beta## -------------------- Gauss (faster alternative) --------------------def gauss(self, mu, sigma):"""Gaussian distribution.mu is the mean, and sigma is the standard deviation. This isslightly faster than the normalvariate() function.Not thread-safe without a lock around calls."""# When x and y are two variables from [0, 1), uniformly# distributed, then## cos(2*pi*x)*sqrt(-2*log(1-y))# sin(2*pi*x)*sqrt(-2*log(1-y))## are two *independent* variables with normal distribution# (mu = 0, sigma = 1).# (Lambert Meertens)# (corrected version; bug discovered by Mike Miller, fixed by LM)# Multithreading note: When two threads call this function# simultaneously, it is possible that they will receive the# same return value. The window is very small though. 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.)random = self.randomz = self.gauss_nextself.gauss_next = Noneif z is None:x2pi = random() * TWOPIg2rad = _sqrt(-2.0 * _log(1.0 - random()))z = _cos(x2pi) * g2radself.gauss_next = _sin(x2pi) * g2radreturn 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.def betavariate(self, alpha, beta):"""Beta distribution.Conditions on the parameters are alpha > 0 and beta > 0.Returned values range between 0 and 1."""# 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.0else:return y / (y + self.gammavariate(beta, 1.0))## -------------------- Pareto --------------------def paretovariate(self, alpha):"""Pareto distribution. alpha is the shape parameter."""# Jain, pg. 495u = 1.0 - self.random()return 1.0 / u ** (1.0/alpha)## -------------------- Weibull --------------------def weibullvariate(self, alpha, beta):"""Weibull distribution.alpha is the scale parameter and beta is the shape parameter."""# Jain, pg. 499; bug fix courtesy Bill Armsu = 1.0 - self.random()return alpha * (-_log(u)) ** (1.0/beta)## --------------- Operating System Random Source ------------------class SystemRandom(Random):"""Alternate random number generator using sources providedby the operating system (such as /dev/urandom on Unix orCryptGenRandom on Windows).Not available on all systems (see os.urandom() for details)."""def random(self):"""Get the next random number in the range [0.0, 1.0)."""return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPFdef getrandbits(self, k):"""getrandbits(k) -> x. Generates an int with k random bits."""if k <= 0:raise ValueError('number of bits must be greater than zero')numbytes = (k + 7) // 8 # bits / 8 and rounded upx = int.from_bytes(_urandom(numbytes), 'big')return x >> (numbytes * 8 - k) # trim excess bitsdef seed(self, *args, **kwds):"Stub method. Not used for a system random number generator."return Nonedef _notimplemented(self, *args, **kwds):"Method should not be called for a system random number generator."raise NotImplementedError('System entropy source does not have state.')getstate = setstate = _notimplemented## -------------------- test program --------------------def _test_generator(n, func, args):import timeprint(n, 'times', func.__name__)total = 0.0sqsum = 0.0smallest = 1e10largest = -1e10t0 = time.perf_counter()for i in range(n):x = func(*args)total += xsqsum = sqsum + x*xsmallest = min(x, smallest)largest = max(x, largest)t1 = time.perf_counter()print(round(t1-t0, 3), 'sec,', end=' ')avg = total/nstddev = _sqrt(sqsum/n - avg*avg)print('avg %g, stddev %g, min %g, max %g\n' % \(avg, stddev, smallest, largest))def _test(N=2000):_test_generator(N, random, ())_test_generator(N, normalvariate, (0.0, 1.0))_test_generator(N, lognormvariate, (0.0, 1.0))_test_generator(N, vonmisesvariate, (0.0, 1.0))_test_generator(N, gammavariate, (0.01, 1.0))_test_generator(N, gammavariate, (0.1, 1.0))_test_generator(N, gammavariate, (0.1, 2.0))_test_generator(N, gammavariate, (0.5, 1.0))_test_generator(N, gammavariate, (0.9, 1.0))_test_generator(N, gammavariate, (1.0, 1.0))_test_generator(N, gammavariate, (2.0, 1.0))_test_generator(N, gammavariate, (20.0, 1.0))_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))# 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# for most programs and is easier for the casual user than making them# instantiate their own Random() instance._inst = Random()seed = _inst.seedrandom = _inst.randomuniform = _inst.uniformtriangular = _inst.triangularrandint = _inst.randintchoice = _inst.choicerandrange = _inst.randrangesample = _inst.sampleshuffle = _inst.shufflechoices = _inst.choicesnormalvariate = _inst.normalvariatelognormvariate = _inst.lognormvariateexpovariate = _inst.expovariatevonmisesvariate = _inst.vonmisesvariategammavariate = _inst.gammavariategauss = _inst.gaussbetavariate = _inst.betavariateparetovariate = _inst.paretovariateweibullvariate = _inst.weibullvariategetstate = _inst.getstatesetstate = _inst.setstategetrandbits = _inst.getrandbitsif hasattr(_os, "fork"):_os.register_at_fork(after_in_child=_inst.seed)if __name__ == '__main__':_test()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。