Add recipe for a version of random() with a larger population (GH-22664)
This commit is contained in:
parent
cfb0f57ff8
commit
8b2ff4c03d
|
@ -391,8 +391,8 @@ change across Python versions, but two aspects are guaranteed not to change:
|
|||
|
||||
.. _random-examples:
|
||||
|
||||
Examples and Recipes
|
||||
--------------------
|
||||
Examples
|
||||
--------
|
||||
|
||||
Basic examples::
|
||||
|
||||
|
@ -516,6 +516,52 @@ Simulation of arrival times and service deliveries for a multiserver queue::
|
|||
print(f'Mean wait: {mean(waits):.1f} Max wait: {max(waits):.1f}')
|
||||
print('Quartiles:', [round(q, 1) for q in quantiles(waits)])
|
||||
|
||||
Recipes
|
||||
-------
|
||||
|
||||
The default :func:`.random` returns multiples of 2⁻⁵³ in the range
|
||||
*0.0 ≤ x < 1.0*. All such numbers are evenly spaced and exactly
|
||||
representable as Python floats. However, many floats in that interval
|
||||
are not possible selections. For example, ``0.05954861408025609``
|
||||
isn't an integer multiple of 2⁻⁵³.
|
||||
|
||||
The following recipe takes a different approach. All floats in the
|
||||
interval are possible selections. Conceptually it works by choosing
|
||||
from evenly spaced multiples of 2⁻¹⁰⁷⁴ and then rounding down to the
|
||||
nearest representable float.
|
||||
|
||||
For efficiency, the actual mechanics involve calling
|
||||
:func:`~math.ldexp` to construct a representable float. The mantissa
|
||||
comes from a uniform distribution of integers in the range *2⁵² ≤
|
||||
mantissa < 2⁵³*. The exponent comes from a geometric distribution
|
||||
where exponents smaller than *-53* occur half as often as the next
|
||||
larger exponent.
|
||||
|
||||
::
|
||||
|
||||
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)
|
||||
|
||||
All of the real valued distributions will use the new method::
|
||||
|
||||
>>> fr = FullRandom()
|
||||
>>> fr.random()
|
||||
0.05954861408025609
|
||||
>>> fr.expovariate(0.25)
|
||||
8.87925541791544
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Statistics for Hackers <https://www.youtube.com/watch?v=Iq9DzN6mvYA>`_
|
||||
|
@ -536,3 +582,8 @@ Simulation of arrival times and service deliveries for a multiserver queue::
|
|||
a tutorial by `Peter Norvig <http://norvig.com/bio.html>`_ covering
|
||||
the basics of probability theory, how to write simulations, and
|
||||
how to perform data analysis using Python.
|
||||
|
||||
`Generating Pseudo-random Floating-Point Values
|
||||
<https://allendowney.com/research/rand/downey07randfloat.pdf>`_ a
|
||||
paper by Allen B. Downey describing ways to generate more
|
||||
fine-grained floats than normally generated by :func:`.random`.
|
||||
|
|
Loading…
Reference in New Issue