Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[3.9] Add recipe for a version of random() with a larger population (GH-22664) #22684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 13, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions Doc/library/random.rst
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ change across Python versions, but two aspects are guaranteed not to change:

.. _random-examples:

Examples and Recipes
--------------------
Examples
--------

Basic examples::

Expand Down Expand Up @@ -516,6 +516,52 @@ 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'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::

`Statistics for Hackers <https://www.youtube.com/watch?v=Iq9DzN6mvYA>`_
Expand All @@ -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`.