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

Skip to content

Commit 63d1522

Browse files
leodemarhettinger
authored andcommitted
bpo-30561: Sync-up expovariate() and gammavariate code (GH-1934)
1 parent b7105c9 commit 63d1522

3 files changed

Lines changed: 36 additions & 15 deletions

File tree

Lib/random.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,7 @@ def gammavariate(self, alpha, beta):
582582

583583
elif alpha == 1.0:
584584
# expovariate(1/beta)
585-
u = random()
586-
while u <= 1e-7:
587-
u = random()
588-
return -_log(u) * beta
585+
return -_log(1.0 - random()) * beta
589586

590587
else: # alpha is between 0 and 1 (exclusive)
591588

Lib/test/test_random.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -853,28 +853,48 @@ def test_gammavariate_errors(self):
853853
self.assertRaises(ValueError, random.gammavariate, 2, 0)
854854
self.assertRaises(ValueError, random.gammavariate, 1, -3)
855855

856+
# There are three different possibilities in the current implementation
857+
# of random.gammavariate(), depending on the value of 'alpha'. What we
858+
# are going to do here is to fix the values returned by random() to
859+
# generate test cases that provide 100% line coverage of the method.
856860
@unittest.mock.patch('random.Random.random')
857-
def test_gammavariate_full_code_coverage(self, random_mock):
858-
# There are three different possibilities in the current implementation
859-
# of random.gammavariate(), depending on the value of 'alpha'. What we
860-
# are going to do here is to fix the values returned by random() to
861-
# generate test cases that provide 100% line coverage of the method.
861+
def test_gammavariate_alpha_greater_one(self, random_mock):
862862

863-
# #1: alpha > 1.0: we want the first random number to be outside the
863+
# #1: alpha > 1.0.
864+
# We want the first random number to be outside the
864865
# [1e-7, .9999999] range, so that the continue statement executes
865866
# once. The values of u1 and u2 will be 0.5 and 0.3, respectively.
866867
random_mock.side_effect = [1e-8, 0.5, 0.3]
867868
returned_value = random.gammavariate(1.1, 2.3)
868869
self.assertAlmostEqual(returned_value, 2.53)
869870

870-
# #2: alpha == 1: first random number less than 1e-7 to that the body
871-
# of the while loop executes once. Then random.random() returns 0.45,
871+
@unittest.mock.patch('random.Random.random')
872+
def test_gammavariate_alpha_equal_one(self, random_mock):
873+
874+
# #2.a: alpha == 1.
875+
# The execution body of the while loop executes once.
876+
# Then random.random() returns 0.45,
872877
# which causes while to stop looping and the algorithm to terminate.
873-
random_mock.side_effect = [1e-8, 0.45]
878+
random_mock.side_effect = [0.45]
874879
returned_value = random.gammavariate(1.0, 3.14)
875-
self.assertAlmostEqual(returned_value, 2.507314166123803)
880+
self.assertAlmostEqual(returned_value, 1.877208182372648)
881+
882+
@unittest.mock.patch('random.Random.random')
883+
def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock):
884+
885+
# #2.b: alpha == 1.
886+
# It must be equivalent of calling expovariate(1.0 / beta).
887+
beta = 3.14
888+
random_mock.side_effect = [1e-8, 1e-8]
889+
gammavariate_returned_value = random.gammavariate(1.0, beta)
890+
expovariate_returned_value = random.expovariate(1.0 / beta)
891+
self.assertAlmostEqual(gammavariate_returned_value, expovariate_returned_value)
892+
893+
@unittest.mock.patch('random.Random.random')
894+
def test_gammavariate_alpha_between_zero_and_one(self, random_mock):
876895

877-
# #3: 0 < alpha < 1. This is the most complex region of code to cover,
896+
# #3: 0 < alpha < 1.
897+
# This is the most complex region of code to cover,
878898
# as there are multiple if-else statements. Let's take a look at the
879899
# source code, and determine the values that we need accordingly:
880900
#
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
random.gammavariate(1.0, beta) now computes the same result as
2+
random.expovariate(1.0 / beta). This synchonizes the two algorithms and
3+
eliminates some idiosyncrasies in the old implementation. It does however
4+
produce a difference stream of random variables than it used to.

0 commit comments

Comments
 (0)