@@ -391,8 +391,8 @@ change across Python versions, but two aspects are guaranteed not to change:
391
391
392
392
.. _random-examples :
393
393
394
- Examples and Recipes
395
- --------------------
394
+ Examples
395
+ --------
396
396
397
397
Basic examples::
398
398
@@ -516,6 +516,52 @@ Simulation of arrival times and service deliveries for a multiserver queue::
516
516
print(f'Mean wait: {mean(waits):.1f}. Stdev wait: {stdev(waits):.1f}.')
517
517
print(f'Median wait: {median(waits):.1f}. Max wait: {max(waits):.1f}.')
518
518
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
+
519
565
.. seealso ::
520
566
521
567
`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::
536
582
a tutorial by `Peter Norvig <http://norvig.com/bio.html >`_ covering
537
583
the basics of probability theory, how to write simulations, and
538
584
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