mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-30561: Sync-up expovariate() and gammavariate code (GH-1934)
This commit is contained in:
		
							parent
							
								
									b7105c9c96
								
							
						
					
					
						commit
						63d152232e
					
				
					 3 changed files with 38 additions and 17 deletions
				
			
		|  | @ -582,10 +582,7 @@ def gammavariate(self, alpha, beta): | ||||||
| 
 | 
 | ||||||
|         elif alpha == 1.0: |         elif alpha == 1.0: | ||||||
|             # expovariate(1/beta) |             # expovariate(1/beta) | ||||||
|             u = random() |             return -_log(1.0 - random()) * beta | ||||||
|             while u <= 1e-7: |  | ||||||
|                 u = random() |  | ||||||
|             return -_log(u) * beta |  | ||||||
| 
 | 
 | ||||||
|         else:   # alpha is between 0 and 1 (exclusive) |         else:   # alpha is between 0 and 1 (exclusive) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -853,28 +853,48 @@ def test_gammavariate_errors(self): | ||||||
|         self.assertRaises(ValueError, random.gammavariate, 2, 0) |         self.assertRaises(ValueError, random.gammavariate, 2, 0) | ||||||
|         self.assertRaises(ValueError, random.gammavariate, 1, -3) |         self.assertRaises(ValueError, random.gammavariate, 1, -3) | ||||||
| 
 | 
 | ||||||
|  |     # There are three different possibilities in the current implementation | ||||||
|  |     # of random.gammavariate(), depending on the value of 'alpha'. What we | ||||||
|  |     # are going to do here is to fix the values returned by random() to | ||||||
|  |     # generate test cases that provide 100% line coverage of the method. | ||||||
|     @unittest.mock.patch('random.Random.random') |     @unittest.mock.patch('random.Random.random') | ||||||
|     def test_gammavariate_full_code_coverage(self, random_mock): |     def test_gammavariate_alpha_greater_one(self, random_mock): | ||||||
|         # There are three different possibilities in the current implementation |  | ||||||
|         # of random.gammavariate(), depending on the value of 'alpha'. What we |  | ||||||
|         # are going to do here is to fix the values returned by random() to |  | ||||||
|         # generate test cases that provide 100% line coverage of the method. |  | ||||||
| 
 | 
 | ||||||
|         # #1: alpha > 1.0: we want the first random number to be outside the |         # #1: alpha > 1.0. | ||||||
|  |         # We want the first random number to be outside the | ||||||
|         # [1e-7, .9999999] range, so that the continue statement executes |         # [1e-7, .9999999] range, so that the continue statement executes | ||||||
|         # once. The values of u1 and u2 will be 0.5 and 0.3, respectively. |         # once. The values of u1 and u2 will be 0.5 and 0.3, respectively. | ||||||
|         random_mock.side_effect = [1e-8, 0.5, 0.3] |         random_mock.side_effect = [1e-8, 0.5, 0.3] | ||||||
|         returned_value = random.gammavariate(1.1, 2.3) |         returned_value = random.gammavariate(1.1, 2.3) | ||||||
|         self.assertAlmostEqual(returned_value, 2.53) |         self.assertAlmostEqual(returned_value, 2.53) | ||||||
| 
 | 
 | ||||||
|         # #2: alpha == 1: first random number less than 1e-7 to that the body |     @unittest.mock.patch('random.Random.random') | ||||||
|         # of the while loop executes once. Then random.random() returns 0.45, |     def test_gammavariate_alpha_equal_one(self, random_mock): | ||||||
|         # which causes while to stop looping and the algorithm to terminate. |  | ||||||
|         random_mock.side_effect = [1e-8, 0.45] |  | ||||||
|         returned_value = random.gammavariate(1.0, 3.14) |  | ||||||
|         self.assertAlmostEqual(returned_value, 2.507314166123803) |  | ||||||
| 
 | 
 | ||||||
|         # #3: 0 < alpha < 1. This is the most complex region of code to cover, |         # #2.a: alpha == 1. | ||||||
|  |         # The execution body of the while loop executes once. | ||||||
|  |         # Then random.random() returns 0.45, | ||||||
|  |         # which causes while to stop looping and the algorithm to terminate. | ||||||
|  |         random_mock.side_effect = [0.45] | ||||||
|  |         returned_value = random.gammavariate(1.0, 3.14) | ||||||
|  |         self.assertAlmostEqual(returned_value, 1.877208182372648) | ||||||
|  | 
 | ||||||
|  |     @unittest.mock.patch('random.Random.random') | ||||||
|  |     def test_gammavariate_alpha_equal_one_equals_expovariate(self, random_mock): | ||||||
|  | 
 | ||||||
|  |         # #2.b: alpha == 1. | ||||||
|  |         # It must be equivalent of calling expovariate(1.0 / beta). | ||||||
|  |         beta = 3.14 | ||||||
|  |         random_mock.side_effect = [1e-8, 1e-8] | ||||||
|  |         gammavariate_returned_value = random.gammavariate(1.0, beta) | ||||||
|  |         expovariate_returned_value = random.expovariate(1.0 / beta) | ||||||
|  |         self.assertAlmostEqual(gammavariate_returned_value, expovariate_returned_value) | ||||||
|  | 
 | ||||||
|  |     @unittest.mock.patch('random.Random.random') | ||||||
|  |     def test_gammavariate_alpha_between_zero_and_one(self, random_mock): | ||||||
|  | 
 | ||||||
|  |         # #3: 0 < alpha < 1. | ||||||
|  |         # This is the most complex region of code to cover, | ||||||
|         # as there are multiple if-else statements. Let's take a look at the |         # as there are multiple if-else statements. Let's take a look at the | ||||||
|         # source code, and determine the values that we need accordingly: |         # source code, and determine the values that we need accordingly: | ||||||
|         # |         # | ||||||
|  |  | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | random.gammavariate(1.0, beta) now computes the same result as | ||||||
|  | random.expovariate(1.0 / beta).  This synchonizes the two algorithms and | ||||||
|  | eliminates some idiosyncrasies in the old implementation.  It does however | ||||||
|  | produce a difference stream of random variables than it used to. | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 leodema
						leodema