mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Improve recipe readability (GH-22685) (GH-22686)
This commit is contained in:
parent
5f0007f0f8
commit
270a2fbc55
1 changed files with 52 additions and 46 deletions
|
@ -253,6 +253,8 @@ Functions for sequences
|
||||||
order so that the sample is reproducible.
|
order so that the sample is reproducible.
|
||||||
|
|
||||||
|
|
||||||
|
.. _real-valued-distributions:
|
||||||
|
|
||||||
Real-valued distributions
|
Real-valued distributions
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
@ -516,52 +518,6 @@ Simulation of arrival times and service deliveries for a multiserver queue::
|
||||||
print(f'Mean wait: {mean(waits):.1f}. Stdev wait: {stdev(waits):.1f}.')
|
print(f'Mean wait: {mean(waits):.1f}. Stdev wait: {stdev(waits):.1f}.')
|
||||||
print(f'Median wait: {median(waits):.1f}. Max wait: {max(waits):.1f}.')
|
print(f'Median wait: {median(waits):.1f}. Max wait: {max(waits):.1f}.')
|
||||||
|
|
||||||
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::
|
.. seealso::
|
||||||
|
|
||||||
`Statistics for Hackers <https://www.youtube.com/watch?v=Iq9DzN6mvYA>`_
|
`Statistics for Hackers <https://www.youtube.com/watch?v=Iq9DzN6mvYA>`_
|
||||||
|
@ -583,6 +539,56 @@ All of the real valued distributions will use the new method::
|
||||||
the basics of probability theory, how to write simulations, and
|
the basics of probability theory, how to write simulations, and
|
||||||
how to perform data analysis using Python.
|
how to perform data analysis using Python.
|
||||||
|
|
||||||
|
|
||||||
|
Recipes
|
||||||
|
-------
|
||||||
|
|
||||||
|
The default :func:`.random` returns multiples of 2⁻⁵³ in the range
|
||||||
|
*0.0 ≤ x < 1.0*. All such numbers are evenly spaced and are 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. 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 :ref:`real valued distributions <real-valued-distributions>`
|
||||||
|
in the class will use the new method::
|
||||||
|
|
||||||
|
>>> fr = FullRandom()
|
||||||
|
>>> fr.random()
|
||||||
|
0.05954861408025609
|
||||||
|
>>> fr.expovariate(0.25)
|
||||||
|
8.87925541791544
|
||||||
|
|
||||||
|
The recipe is conceptually equivalent to an algorithm that chooses from
|
||||||
|
all the multiples of 2⁻¹⁰⁷⁴ in the range *0.0 ≤ x < 1.0*. All such
|
||||||
|
numbers are evenly spaced, but most have to be rounded down to the
|
||||||
|
nearest representable Python float. (The value 2⁻¹⁰⁷⁴ is the smallest
|
||||||
|
positive unnormalized float and is equal to ``math.ulp(0.0)``.)
|
||||||
|
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
`Generating Pseudo-random Floating-Point Values
|
`Generating Pseudo-random Floating-Point Values
|
||||||
<https://allendowney.com/research/rand/downey07randfloat.pdf>`_ a
|
<https://allendowney.com/research/rand/downey07randfloat.pdf>`_ a
|
||||||
paper by Allen B. Downey describing ways to generate more
|
paper by Allen B. Downey describing ways to generate more
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue