diff options
Diffstat (limited to 'Doc/library/random.rst')
-rw-r--r-- | Doc/library/random.rst | 67 |
1 files changed, 62 insertions, 5 deletions
diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 4e97b1dbad..5a9359484d 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -57,7 +57,7 @@ from sources provided by the operating system. `Complementary-Multiply-with-Carry recipe - <https://github.com/ActiveState/code/tree/master/recipes/Python/576707_Long_period_random_number/recipe-576707.py>`_ for a compatible alternative + <https://code.activestate.com/recipes/576707/>`_ for a compatible alternative random number generator with a long period and comparatively simple update operations. @@ -180,8 +180,8 @@ Functions for sequences The *weights* or *cum_weights* can use any numeric type that interoperates with the :class:`float` values returned by :func:`random` (that includes - integers, floats, and fractions but excludes decimals). Behavior is - undefined if any weight is negative. A :exc:`ValueError` is raised if all + integers, floats, and fractions but excludes decimals). Weights are assumed + to be non-negative and finite. A :exc:`ValueError` is raised if all weights are zero. For a given seed, the :func:`choices` function with equal weighting @@ -253,6 +253,8 @@ Functions for sequences order so that the sample is reproducible. +.. _real-valued-distributions: + Real-valued distributions ------------------------- @@ -391,8 +393,8 @@ change across Python versions, but two aspects are guaranteed not to change: .. _random-examples: -Examples and Recipes --------------------- +Examples +-------- Basic examples:: @@ -536,3 +538,58 @@ 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. + + +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 other representable +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 + <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`. |