"random" --- 의사 난수 생성
***************************

**소스 코드:** Lib/random.py

======================================================================

이 모듈은 다양한 분포에 대한 의사 난수 생성기를 구현합니다.

정수에 대해서는, 범위에서 균일한 선택이 있습니다. 시퀀스에 대해서는,
무작위 요소의 균일한 선택, 리스트를 제자리(in-place)에서 임의 순열을
생성하는 함수 및 중복 없는(without replacement) 무작위 표본 추출
(sampling)을 위한 함수가 있습니다.

실수에 대해서는, 균일(uniform), 정규(normal) (가우시안(Gaussian)), 로
그 정규(lognormal), 음의 지수(negative exponential), 감마(gamma) 및 베
타(beta) 분포를 계산하는 함수가 있습니다. 각도 분포를 생성하기 위해,
폰 미제스(von Mises) 분포를 사용할 수 있습니다.

Almost all module functions depend on the basic function "random()",
which generates a random float uniformly in the half-open range "0.0
<= X < 1.0". Python uses the Mersenne Twister as the core generator.
It produces 53-bit precision floats and has a period of 2**19937-1.
The underlying implementation in C is both fast and threadsafe.  The
Mersenne Twister is one of the most extensively tested random number
generators in existence.  However, being completely deterministic, it
is not suitable for all purposes, and is completely unsuitable for
cryptographic purposes.

이 모듈에서 제공하는 함수는 실제로는 "random.Random" 클래스의 숨겨진
인스턴스에 대해 연결된 메서드입니다. "Random" 인스턴스를 직접 인스턴스
화하여 상태를 공유하지 않는 생성기를 얻을 수 있습니다.

Class "Random" can also be subclassed if you want to use a different
basic generator of your own devising: see the documentation on that
class for more details.

"random" 모듈은 운영 체제에서 제공하는 소스에서 난수를 생성하는 시스템
함수 "os.urandom()"을 사용하는 "SystemRandom" 클래스도 제공합니다.

경고:

  이 모듈의 의사 난수 생성기를 보안 목적으로 사용해서는 안 됩니다. 보
  안이나 암호화 용도를 위해서는, "secrets" 모듈을 참조하십시오.

더 보기:

  M. Matsumoto and T. Nishimura, "Mersenne Twister: A
  623-dimensionally equidistributed uniform pseudorandom number
  generator", ACM Transactions on Modeling and Computer Simulation
  Vol. 8, No. 1, January pp.3--30 1998.

  긴 주기와 비교적 간단한 업데이트 연산을 하는 호환 가능한 대체 난수
  생성기를 위한 Complementary-Multiply-with-Carry recipe


관리 함수
=========

random.seed(a=None, version=2)

   난수 생성기를 초기화합니다.

   *a*가 생략되거나 "None"이면, 현재 시스템 시간이 사용됩니다. 운영 체
   제에서 임의성 소스(randomness sources)를 제공하면, 시스템 시간 대신
   사용됩니다 (가용성에 대한 자세한 내용은 "os.urandom()" 함수를 참조
   하십시오).

   *a*가 int이면, 직접 사용됩니다.

   버전(version) 2(기본값)에서는, "str", "bytes" 또는 "bytearray" 객체
   가 "int"로 변환되어 모든 비트가 사용됩니다.

   버전(version) 1(이전 버전의 파이썬에서 온 임의의 시퀀스를 재현하기
   위해 제공됩니다)에서는, "str"과 "bytes"를 위한 알고리즘은 더 좁은
   범위의 시드(seed)를 생성합니다.

   버전 3.2에서 변경: 문자열 시드의 모든 비트를 사용하는 버전 2 체계로
   이동했습니다.

   버전 3.11에서 변경: The *seed* must be one of the following types:
   "None", "int", "float", "str", "bytes", or "bytearray".

random.getstate()

   생성기의 현재 내부 상태를 포착하는 객체를 반환합니다. 이 객체는
   "setstate()"로 전달되어 상태를 복원 할 수 있습니다.

random.setstate(state)

   *state*는 "getstate()"에 대한 이전 호출에서 얻은 것이어야 하고,
   "setstate()"는 생성기의 내부 상태를 "getstate()"가 호출될 당시의 상
   태로 복원합니다.


바이트열 함수
=============

random.randbytes(n)

   *n* 무작위 바이트를 생성합니다.

   이 메서드를 사용하여 보안 토큰을 생성해서는 안 됩니다. 대신
   "secrets.token_bytes()"를 사용하십시오.

   버전 3.9에 추가.


정수 함수
=========

random.randrange(stop)
random.randrange(start, stop[, step])

   "range(start, stop, step)"에서 임의로 선택된 요소를 반환합니다. 이
   것은 "choice(range(start, stop, step))"와 동등하지만, 실제로 range
   객체를 만들지는 않습니다.

   위치 인자 패턴은 "range()"와 일치합니다. 함수가 예상치 못한 방식으
   로 키워드 인자를 사용할 수 있기 때문에 키워드 인자를 사용해서는 안
   됩니다.

   버전 3.2에서 변경: "randrange()"는 균일하게 분포된 값을 생성하는 데
   있어 더욱 정교합니다. 이전에는 약간 고르지 않은 분포를 생성 할 수
   있는 "int(random()*n)"와 같은 스타일을 사용했습니다.

   버전 3.10부터 폐지됨: The automatic conversion of non-integer types
   to equivalent integers is deprecated.  Currently "randrange(10.0)"
   is losslessly converted to "randrange(10)".  In the future, this
   will raise a "TypeError".

   버전 3.10부터 폐지됨: The exception raised for non-integer values
   such as "randrange(10.5)" or "randrange('10')" will be changed from
   "ValueError" to "TypeError".

random.randint(a, b)

   "a <= N <= b"를 만족하는 임의의 정수 *N*을 반환합니다.
   "randrange(a, b+1)"의 별칭.

random.getrandbits(k)

   *k* 임의의 비트를 갖는 음이 아닌 파이썬 정수를 반환합니다. 이 메서
   드는 메르센 트위스터(Mersenne Twister) 생성기와 함께 제공되며, 일부
   다른 생성기도 API의 선택적 부분으로 제공할 수 있습니다. 사용 가능할
   때, "getrandbits()"는 "randrange()"가 임의로 넓은 범위를 처리 할 수
   있도록 합니다.

   버전 3.9에서 변경: 이 메서드는 이제 *k*에 0을 허용합니다.


시퀀스 함수
===========

random.choice(seq)

   비어 있지 않은 시퀀스 *seq*에서 임의의 요소를 반환합니다. *seq*가
   비어 있으면, "IndexError"를 발생시킵니다.

random.choices(population, weights=None, *, cum_weights=None, k=1)

   *population*에서 중복을 허락하면서(with replacement) 선택한 *k* 크
   기의 요소 리스트를 반환합니다. *population*이 비어 있으면,
   "IndexError"를 발생시킵니다.

   *weights* 시퀀스가 지정되면, 상대 가중치에 따라 선택됩니다. 대안적
   으로, *cum_weights* 시퀀스가 제공되면, (아마도
   "itertools.accumulate()"를 사용하여 계산된) 누적 가중치(cumulative
   weights)에 따라 선택이 이루어집니다. 예를 들어, 상대 가중치 "[10,
   5, 30, 5]"는 누적 가중치 "[10, 15, 45, 50]"과 동등합니다. 내부적으
   로, 상대 가중치는 선택하기 전에 누적 가중치로 변환되므로, 누적 가중
   치를 제공하면 작업이 줄어듭니다.

   *weights*나 *cum_weights*를 지정하지 않으면, 같은 확률로 선택됩니다
   . weights 시퀀스가 제공되면, *population* 시퀀스와 길이가 같아야 합
   니다. *weights*와 *cum_weights*를 모두 지정하는 것은 "TypeError"입
   니다.

   The *weights* or *cum_weights* can use any numeric type that
   interoperates with the "float" values returned by "random()" (that
   includes integers, floats, and fractions but excludes decimals).
   Weights are assumed to be non-negative and finite.  A "ValueError"
   is raised if all weights are zero.

   주어진 시드에 대해, 균등한 가중치를 갖는 "choices()" 함수는 일반적
   으로 "choice()"에 대한 반복 호출과는 다른 시퀀스를 생성합니다.
   "choices()"에서 사용하는 알고리즘은 내부 일관성과 속도를 위해 부동
   소수점 산술을 사용합니다. "choice()"에서 사용하는 알고리즘은 자리
   올림 오차로 인한 작은 바이어스(bias)를 피하려고 반복 선택을 통한 정
   수 산술로 기본 설정됩니다.

   버전 3.6에 추가.

   버전 3.9에서 변경: 모든 가중치가 0이면 "ValueError"를 발생시킵니다.

random.shuffle(x)

   시퀀스 *x*를 제자리에서 섞습니다.

   불변 시퀀스를 섞고 새로운 섞인 리스트를 반환하려면, 대신 "sample(x,
   k=len(x))"를 사용하십시오.

   작은 "len(x)"의 경우에조차, *x*의 총 순열 수는 대부분의 난수 생성기
   주기보다 빠르게 커질 수 있습니다. 이것은 긴 시퀀스의 대부분 순열이
   절대로 생성될 수 없음을 의미합니다. 예를 들어, 길이가 2080인 시퀀스
   가 메르센 트위스터 난수 생성기의 주기 안에 들어갈 수 있는 최대입니
   다.

   버전 3.11에서 변경: Removed the optional parameter *random*.

random.sample(population, k, *, counts=None)

   Return a *k* length list of unique elements chosen from the
   population sequence.  Used for random sampling without replacement.

   원래 population을 변경하지 않고, population의 요소를 포함하는 새 리
   스트를 반환합니다. 결과 리스트는 선택 순서를 따라서, 모든 서브 슬라
   이스도 유효한 임의의 표본이 됩니다. 이것은 추첨 당첨자(표본)를 대상
   (grand prize)과 차점자들(서브 슬라이스)로 나눌 수 있도록 합니다.

   population의 멤버는 *해시 가능*하거나 고유할 필요가 없습니다.
   population이 반복을 포함하면, 각 등장(occurrence)은 표본에서 가능한
   선택입니다.

   반복되는 요소는 한 번에 하나씩 또는 선택적 키워드 전용 *counts* 매
   개 변수로 지정할 수 있습니다. 예를 들어 "sample(['red', 'blue'],
   counts=[4, 2], k=5)"는 "sample(['red', 'red', 'red', 'red', 'blue',
   'blue'], k=5)"와 동등합니다.

   정수 범위에서 표본을 선택하려면, "range()" 객체를 인자로 사용하십시
   오. 이는 큰 population에서 표본 추출할 때 특히 빠르고 공간 효율적입
   니다: "sample(range(10000000), k=60)".

   표본 크기가 population 크기보다 크면 "ValueError"가 발생합니다.

   버전 3.9에서 변경: *counts* 매개 변수를 추가했습니다.

   버전 3.11에서 변경: The *population* must be a sequence.  Automatic
   conversion of sets to lists is no longer supported.


실수 분포
=========

다음 함수는 특정 실수 분포를 생성합니다. 함수 매개 변수는 일반적인 수
학적 관행에 사용되는 분포 방정식에서 해당 변수의 이름을 따서 명명됩니
다; 이러한 방정식의 대부분은 모든 통계 교과서에서 찾을 수 있습니다.

random.random()

   Return the next random floating point number in the range "0.0 <= X
   < 1.0"

random.uniform(a, b)

   "a <= b" 일 때 "a <= N <= b", "b < a" 일 때 "b <= N <= a"를 만족하
   는 임의의 부동 소수점 숫자 *N*을 반환합니다.

   The end-point value "b" may or may not be included in the range
   depending on floating-point rounding in the expression "a + (b-a) *
   random()".

random.triangular(low, high, mode)

   "low <= N <= high"를 만족하고 이 경계 사이에 지정된 *모드(mode)*를
   갖는 임의의 부동 소수점 숫자 *N*을 반환합니다. *low* 및 *high* 경계
   는 기본적으로 0과 1입니다. *mode* 인자는 기본적으로 경계 사이의 중
   간 점으로, 대칭 분포를 제공합니다.

random.betavariate(alpha, beta)

   베타 분포. 매개 변수의 조건은 "alpha > 0"과 "beta > 0"입니다. 반환
   된 값의 범위는 0에서 1입니다.

random.expovariate(lambd)

   지수 분포. *lambd*는 1.0을 원하는 평균으로 나눈 값입니다. 0이 아니
   어야 합니다. (매개 변수는 "lambda"라고 부르지만, 파이썬에서는 예약
   어입니다.) 반환된 값의 범위는, *lambd*가 양수이면 0에서 양의 무한대
   이고, *lambd*가 음수이면 음의 무한대에서 0입니다.

random.gammavariate(alpha, beta)

   Gamma distribution.  (*Not* the gamma function!)  The shape and
   scale parameters, *alpha* and *beta*, must have positive values.
   (Calling conventions vary and some sources define 'beta' as the
   inverse of the scale).

   확률 분포 함수는 다음과 같습니다:

                x ** (alpha - 1) * math.exp(-x / beta)
      pdf(x) =  --------------------------------------
                  math.gamma(alpha) * beta ** alpha

random.gauss(mu=0.0, sigma=1.0)

   Normal distribution, also called the Gaussian distribution. *mu* is
   the mean, and *sigma* is the standard deviation.  This is slightly
   faster than the "normalvariate()" function defined below.

   다중 스레딩 참고: 두 스레드가 이 함수를 동시에 호출하면, 같은 반환
   값을 받을 수 있습니다. 이것은 세 가지 방법으로 피할 수 있습니다. 1)
   각 스레드가 난수 생성기의 다른 인스턴스를 사용하도록 합니다. 2) 모
   든 호출에 록을 둡니다. 3) 더 느리지만, 스레드 안전한
   "normalvariate()" 함수를 대신 사용합니다.

   버전 3.11에서 변경: *mu* and *sigma* now have default arguments.

random.lognormvariate(mu, sigma)

   로그 정규 분포. 이 분포의 자연로그를 취하면, 평균 *mu*와 표준 편차
   *sigma*를 갖는 정규 분포를 얻게 됩니다. *mu*는 아무 값이나 될 수 있
   으며, *sigma*는 0보다 커야 합니다.

random.normalvariate(mu=0.0, sigma=1.0)

   정규 분포. *mu*는 평균이고, *sigma*는 표준 편차입니다.

   버전 3.11에서 변경: *mu* and *sigma* now have default arguments.

random.vonmisesvariate(mu, kappa)

   *mu*는 0과 2**pi* 사이의 라디안으로 표현된 평균 각도이며, *kappa*는
   0 이상이어야 하는 집중도(concentration) 매개 변수입니다.  *kappa*가
   0이면, 이 분포는 0에서 2**pi*에 걸친 균등한 임의의 각도로 환원됩니
   다.

random.paretovariate(alpha)

   파레토 분포. *alpha*는 모양(shape) 매개 변수입니다.

random.weibullvariate(alpha, beta)

   베이불 분포. *alpha*는 크기(scale) 매개 변수이고 *beta*는 모양
   (shape) 매개 변수입니다.


대체 생성기
===========

class random.Random([seed])

   "random" 모듈에서 사용하는 기본 의사 난수 생성기를 구현하는 클래스.

   버전 3.11에서 변경: Formerly the *seed* could be any hashable
   object.  Now it is limited to: "None", "int", "float", "str",
   "bytes", or "bytearray".

   Subclasses of "Random" should override the following methods if
   they wish to make use of a different basic generator:

   seed(a=None, version=2)

      Override this method in subclasses to customise the "seed()"
      behaviour of "Random" instances.

   getstate()

      Override this method in subclasses to customise the "getstate()"
      behaviour of "Random" instances.

   setstate(state)

      Override this method in subclasses to customise the "setstate()"
      behaviour of "Random" instances.

   random()

      Override this method in subclasses to customise the "random()"
      behaviour of "Random" instances.

   Optionally, a custom generator subclass can also supply the
   following method:

   getrandbits(k)

      Override this method in subclasses to customise the
      "getrandbits()" behaviour of "Random" instances.

class random.SystemRandom([seed])

   운영 체제에서 제공하는 소스에서 난수를 생성하기 위해 "os.urandom()"
   함수를 사용하는 클래스. 모든 시스템에서 사용 가능한 것은 아닙니다.
   소프트웨어 상태에 의존하지 않으며, 시퀀스는 재현되지 않습니다. 따라
   서, "seed()" 메서드는 효과가 없으며, 무시됩니다. "getstate()"와
   "setstate()" 메서드는 호출되면 "NotImplementedError"를 발생시킵니다
   .


재현성에 대한 참고 사항
=======================

때때로 의사 난수 생성기가 만든 시퀀스를 재현하는 것이 유용 할 수 있습
니다. 시드 값을 재사용하면, 여러 스레드가 실행되고 있지 않은 한 실행할
때마다 같은 시퀀스를 재현할 수 있어야 합니다.

random 모듈의 알고리즘과 시딩(seeding) 함수의 대부분은 파이썬 버전에
따라 변경될 수 있지만, 두 가지 측면은 변경되지 않음이 보장됩니다:

* 새로운 시딩 메서드가 추가되면, 이전 버전과 호환되는 시더(seeder)가
  제공될 것입니다.

* 호환 시더에 같은 시드가 제공되면 생성기의 "random()" 메서드는 같은
  시퀀스를 계속 생성할 것입니다.


예제
====

기본 예제:

   >>> random()                          # Random float:  0.0 <= x < 1.0
   0.37444887175646646

   >>> uniform(2.5, 10.0)                # Random float:  2.5 <= x <= 10.0
   3.1800146073117523

   >>> expovariate(1 / 5)                # Interval between arrivals averaging 5 seconds
   5.148957571865031

   >>> randrange(10)                     # Integer from 0 to 9 inclusive
   7

   >>> randrange(0, 101, 2)              # Even integer from 0 to 100 inclusive
   26

   >>> choice(['win', 'lose', 'draw'])   # Single random element from a sequence
   'draw'

   >>> deck = 'ace two three four'.split()
   >>> shuffle(deck)                     # Shuffle a list
   >>> deck
   ['four', 'two', 'ace', 'three']

   >>> sample([10, 20, 30, 40, 50], k=4) # Four samples without replacement
   [40, 10, 50, 30]

시뮬레이션:

   >>> # Six roulette wheel spins (weighted sampling with replacement)
   >>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
   ['red', 'green', 'black', 'black', 'red', 'black']

   >>> # Deal 20 cards without replacement from a deck
   >>> # of 52 playing cards, and determine the proportion of cards
   >>> # with a ten-value:  ten, jack, queen, or king.
   >>> dealt = sample(['tens', 'low cards'], counts=[16, 36], k=20)
   >>> dealt.count('tens') / 20
   0.15

   >>> # Estimate the probability of getting 5 or more heads from 7 spins
   >>> # of a biased coin that settles on heads 60% of the time.
   >>> def trial():
   ...     return choices('HT', cum_weights=(0.60, 1.00), k=7).count('H') >= 5
   ...
   >>> sum(trial() for i in range(10_000)) / 10_000
   0.4169

   >>> # Probability of the median of 5 samples being in middle two quartiles
   >>> def trial():
   ...     return 2_500 <= sorted(choices(range(10_000), k=5))[2] < 7_500
   ...
   >>> sum(trial() for i in range(10_000)) / 10_000
   0.7958

표본의 평균에 대한 신뢰 구간을 추정하기 위해 중복을 허용하는(with
replacement) 재표본추출(resampling)을 사용하는 통계적 부트스트래핑
(statistical bootstrapping)의 예:

   # https://www.thoughtco.com/example-of-bootstrapping-3126155
   from statistics import fmean as mean
   from random import choices

   data = [41, 50, 29, 37, 81, 30, 73, 63, 20, 35, 68, 22, 60, 31, 95]
   means = sorted(mean(choices(data, k=len(data))) for i in range(100))
   print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
         f'interval from {means[5]:.1f} to {means[94]:.1f}')

약물과 위약의 효과 간에 관찰된 차이의 통계적 유의성 또는 p-값을 결정하
기 위한 재표본추출 순열 검증(resampling permutation test)의 예:

   # Example from "Statistics is Easy" by Dennis Shasha and Manda Wilson
   from statistics import fmean as mean
   from random import shuffle

   drug = [54, 73, 53, 70, 73, 68, 52, 65, 65]
   placebo = [54, 51, 58, 44, 55, 52, 42, 47, 58, 46]
   observed_diff = mean(drug) - mean(placebo)

   n = 10_000
   count = 0
   combined = drug + placebo
   for i in range(n):
       shuffle(combined)
       new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):])
       count += (new_diff >= observed_diff)

   print(f'{n} label reshufflings produced only {count} instances with a difference')
   print(f'at least as extreme as the observed difference of {observed_diff:.1f}.')
   print(f'The one-sided p-value of {count / n:.4f} leads us to reject the null')
   print(f'hypothesis that there is no difference between the drug and the placebo.')

다중 서버 큐를 위한 도착 시간과 서비스 제공의 시뮬레이션:

   from heapq import heapify, heapreplace
   from random import expovariate, gauss
   from statistics import mean, quantiles

   average_arrival_interval = 5.6
   average_service_time = 15.0
   stdev_service_time = 3.5
   num_servers = 3

   waits = []
   arrival_time = 0.0
   servers = [0.0] * num_servers  # time when each server becomes available
   heapify(servers)
   for i in range(1_000_000):
       arrival_time += expovariate(1.0 / average_arrival_interval)
       next_server_available = servers[0]
       wait = max(0.0, next_server_available - arrival_time)
       waits.append(wait)
       service_duration = max(0.0, gauss(average_service_time, stdev_service_time))
       service_completed = arrival_time + wait + service_duration
       heapreplace(servers, service_completed)

   print(f'Mean wait: {mean(waits):.1f}   Max wait: {max(waits):.1f}')
   print('Quartiles:', [round(q, 1) for q in quantiles(waits)])

더 보기:

  시뮬레이션(simulation), 표본 추출(sampling), 섞기(shuffling) 및 교차
  검증(cross-validation)을 포함하는 몇 가지 기본 개념만을 사용한, 통계
  분석에 대한 Jake Vanderplas의 비디오 자습서 Statistics for Hackers

  Economics Simulation a simulation of a marketplace by Peter Norvig
  that shows effective use of many of the tools and distributions
  provided by this module (gauss, uniform, sample, betavariate,
  choice, triangular, and randrange).

  A Concrete Introduction to Probability (using Python) a tutorial by
  Peter Norvig covering the basics of probability theory, how to write
  simulations, and how to perform data analysis using Python.


조리법
======

These recipes show how to efficiently make random selections from the
combinatoric iterators in the "itertools" module:

   def random_product(*args, repeat=1):
       "Random selection from itertools.product(*args, **kwds)"
       pools = [tuple(pool) for pool in args] * repeat
       return tuple(map(random.choice, pools))

   def random_permutation(iterable, r=None):
       "Random selection from itertools.permutations(iterable, r)"
       pool = tuple(iterable)
       r = len(pool) if r is None else r
       return tuple(random.sample(pool, r))

   def random_combination(iterable, r):
       "Random selection from itertools.combinations(iterable, r)"
       pool = tuple(iterable)
       n = len(pool)
       indices = sorted(random.sample(range(n), r))
       return tuple(pool[i] for i in indices)

   def random_combination_with_replacement(iterable, r):
       "Choose r elements with replacement.  Order the result to match the iterable."
       # Result will be in set(itertools.combinations_with_replacement(iterable, r)).
       pool = tuple(iterable)
       n = len(pool)
       indices = sorted(random.choices(range(n), k=r))
       return tuple(pool[i] for i in indices)

기본 "random()"은 *0.0 ≤ x < 1.0* 범위에서 2⁻⁵³의 배수를 반환합니다.
이러한 모든 숫자는 균등 간격으로 분포되어있고 파이썬 float로 정확하게
표현할 수 있습니다. 그러나, 해당 범위의 다른 많은 표현 가능한 부동 소
수점은 가능한 선택이 아닙니다. 예를 들어, "0.05954861408025609"는 2⁻⁵³
의 정수배가 아닙니다.

다음 조리법은 다른 접근 방식을 사용합니다. 범위의 모든 부동 소수점이
가능한 선택입니다. 가수(mantissa)는 *2⁵² ≤ mantissa < 2⁵³* 범위에 있는
정수의 균등 분포(uniform distribution)에서 옵니다. 지수(exponent)는
*-53*보다 작은 지수가 다음으로 큰 지수의 절반만큼 자주 발생하는 기하
분포(geometric distribution)에서 옵니다.

   from random import Random
   from math import ldexp

   class FullRandom(Random):

       def random(self):
           mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
           exponent = -53
           x = 0
           while not x:
               x = self.getrandbits(32)
               exponent += x.bit_length() - 32
           return ldexp(mantissa, exponent)

클래스의 모든 실숫값 분포는 새 메서드를 사용합니다:

   >>> fr = FullRandom()
   >>> fr.random()
   0.05954861408025609
   >>> fr.expovariate(0.25)
   8.87925541791544

조리법은 개념적으로 *0.0 ≤ x < 1.0* 범위의 2⁻¹⁰⁷⁴의 모든 배수에서 선택
하는 알고리즘과 동등합니다. 이러한 모든 숫자는 균등한 간격이지만, 대부
분은 가장 가까운 표현 가능한 파이썬 부동 소수점으로 자리 내림해야 합니
다. (값 2⁻¹⁰⁷⁴은 가장 작은 양의 정규화되지 않은 부동 소수점이며
"math.ulp(0.0)"과 같습니다.)

더 보기:

  Generating Pseudo-random Floating-Point Values Allen B. Downey의 논
  문은 "random()"이 일반적으로 생성하는 것보다 더 세밀한 부동 소수점을
  생성하는 방법을 설명합니다.
