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

Skip to content

Commit 5f0007f

Browse files
Add recipe for a version of random() with a larger population (GH-22664) (GH-22684)
1 parent afe8606 commit 5f0007f

File tree

1 file changed

+53
-2
lines changed

1 file changed

+53
-2
lines changed

Doc/library/random.rst

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ change across Python versions, but two aspects are guaranteed not to change:
391391

392392
.. _random-examples:
393393

394-
Examples and Recipes
395-
--------------------
394+
Examples
395+
--------
396396

397397
Basic examples::
398398

@@ -516,6 +516,52 @@ Simulation of arrival times and service deliveries for a multiserver queue::
516516
print(f'Mean wait: {mean(waits):.1f}. Stdev wait: {stdev(waits):.1f}.')
517517
print(f'Median wait: {median(waits):.1f}. Max wait: {max(waits):.1f}.')
518518

519+
Recipes
520+
-------
521+
522+
The default :func:`.random` returns multiples of 2⁻⁵³ in the range
523+
*0.0 ≤ x < 1.0*. All such numbers are evenly spaced and exactly
524+
representable as Python floats. However, many floats in that interval
525+
are not possible selections. For example, ``0.05954861408025609``
526+
isn't an integer multiple of 2⁻⁵³.
527+
528+
The following recipe takes a different approach. All floats in the
529+
interval are possible selections. Conceptually it works by choosing
530+
from evenly spaced multiples of 2⁻¹⁰⁷⁴ and then rounding down to the
531+
nearest representable float.
532+
533+
For efficiency, the actual mechanics involve calling
534+
:func:`~math.ldexp` to construct a representable float. The mantissa
535+
comes from a uniform distribution of integers in the range *2⁵² ≤
536+
mantissa < 2⁵³*. The exponent comes from a geometric distribution
537+
where exponents smaller than *-53* occur half as often as the next
538+
larger exponent.
539+
540+
::
541+
542+
from random import Random
543+
from math import ldexp
544+
545+
class FullRandom(Random):
546+
547+
def random(self):
548+
mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
549+
exponent = -53
550+
x = 0
551+
while not x:
552+
x = self.getrandbits(32)
553+
exponent += x.bit_length() - 32
554+
return ldexp(mantissa, exponent)
555+
556+
All of the real valued distributions will use the new method::
557+
558+
>>> fr = FullRandom()
559+
>>> fr.random()
560+
0.05954861408025609
561+
>>> fr.expovariate(0.25)
562+
8.87925541791544
563+
564+
519565
.. seealso::
520566

521567
`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::
536582
a tutorial by `Peter Norvig <http://norvig.com/bio.html>`_ covering
537583
the basics of probability theory, how to write simulations, and
538584
how to perform data analysis using Python.
585+
586+
`Generating Pseudo-random Floating-Point Values
587+
<https://allendowney.com/research/rand/downey07randfloat.pdf>`_ a
588+
paper by Allen B. Downey describing ways to generate more
589+
fine-grained floats than normally generated by :func:`.random`.

0 commit comments

Comments
 (0)