-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
bpo-40282: Allow random.getrandbits(0) #19539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f572b53
3153f1a
9cac35f
b01be91
e7c2e99
5e02ef8
c4673f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -261,6 +261,8 @@ def randint(self, a, b): | |||||
| def _randbelow_with_getrandbits(self, n): | ||||||
| "Return a random int in the range [0,n). Raises ValueError if n==0." | ||||||
|
|
||||||
| if not n: | ||||||
| raise ValueError("Boundary cannot be zero") | ||||||
| getrandbits = self.getrandbits | ||||||
| k = n.bit_length() # don't use (n-1) here because n can be 1 | ||||||
|
||||||
| k = n.bit_length() # don't use (n-1) here because n can be 1 | |
| k = (n-1).bit_length() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to ensure that the values produced for a given seed don't change, so we probably can't change this anymore.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -263,6 +263,31 @@ def test_gauss(self): | |
| self.assertEqual(x1, x2) | ||
| self.assertEqual(y1, y2) | ||
|
|
||
| def test_getrandbits(self): | ||
| # Verify ranges | ||
| for k in range(1, 1000): | ||
| self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) | ||
| self.assertEqual(self.gen.getrandbits(0), 0) | ||
|
|
||
| # Verify all bits active | ||
| getbits = self.gen.getrandbits | ||
| for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: | ||
| all_bits = 2**span-1 | ||
| cum = 0 | ||
| cpl_cum = 0 | ||
| for i in range(100): | ||
| v = getbits(span) | ||
| cum |= v | ||
| cpl_cum |= all_bits ^ v | ||
| self.assertEqual(cum, all_bits) | ||
| self.assertEqual(cpl_cum, all_bits) | ||
|
||
|
|
||
| # Verify argument checking | ||
| self.assertRaises(TypeError, self.gen.getrandbits) | ||
| self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) | ||
| self.assertRaises(ValueError, self.gen.getrandbits, -1) | ||
| self.assertRaises(TypeError, self.gen.getrandbits, 10.1) | ||
|
|
||
| def test_pickling(self): | ||
| for proto in range(pickle.HIGHEST_PROTOCOL + 1): | ||
| state = pickle.dumps(self.gen, proto) | ||
|
|
@@ -374,26 +399,6 @@ def test_randrange_errors(self): | |
| raises(0, 42, 0) | ||
| raises(0, 42, 3.14159) | ||
|
|
||
| def test_genrandbits(self): | ||
| # Verify ranges | ||
| for k in range(1, 1000): | ||
| self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) | ||
|
|
||
| # Verify all bits active | ||
| getbits = self.gen.getrandbits | ||
| for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: | ||
| cum = 0 | ||
| for i in range(100): | ||
| cum |= getbits(span) | ||
| self.assertEqual(cum, 2**span-1) | ||
|
|
||
| # Verify argument checking | ||
| self.assertRaises(TypeError, self.gen.getrandbits) | ||
| self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) | ||
| self.assertRaises(ValueError, self.gen.getrandbits, 0) | ||
| self.assertRaises(ValueError, self.gen.getrandbits, -1) | ||
| self.assertRaises(TypeError, self.gen.getrandbits, 10.1) | ||
|
|
||
| def test_randbelow_logic(self, _log=log, int=int): | ||
| # check bitcount transition points: 2**i and 2**(i+1)-1 | ||
| # show that: k = int(1.001 + _log(n, 2)) | ||
|
|
@@ -613,34 +618,18 @@ def test_rangelimits(self): | |
| self.assertEqual(set(range(start,stop)), | ||
| set([self.gen.randrange(start,stop) for i in range(100)])) | ||
|
|
||
| def test_genrandbits(self): | ||
| def test_getrandbits(self): | ||
| super().test_getrandbits() | ||
|
|
||
| # Verify cross-platform repeatability | ||
| self.gen.seed(1234567) | ||
| self.assertEqual(self.gen.getrandbits(100), | ||
| 97904845777343510404718956115) | ||
| # Verify ranges | ||
| for k in range(1, 1000): | ||
| self.assertTrue(0 <= self.gen.getrandbits(k) < 2**k) | ||
|
|
||
| # Verify all bits active | ||
| getbits = self.gen.getrandbits | ||
| for span in [1, 2, 3, 4, 31, 32, 32, 52, 53, 54, 119, 127, 128, 129]: | ||
| cum = 0 | ||
| for i in range(100): | ||
| cum |= getbits(span) | ||
| self.assertEqual(cum, 2**span-1) | ||
|
|
||
| # Verify argument checking | ||
| self.assertRaises(TypeError, self.gen.getrandbits) | ||
| self.assertRaises(TypeError, self.gen.getrandbits, 'a') | ||
| self.assertRaises(TypeError, self.gen.getrandbits, 1, 2) | ||
| self.assertRaises(ValueError, self.gen.getrandbits, 0) | ||
| self.assertRaises(ValueError, self.gen.getrandbits, -1) | ||
|
|
||
| def test_randrange_uses_getrandbits(self): | ||
| # Verify use of getrandbits by randrange | ||
| # Use same seed as in the cross-platform repeatability test | ||
| # in test_genrandbits above. | ||
| # in test_getrandbits above. | ||
| self.gen.seed(1234567) | ||
| # If randrange uses getrandbits, it should pick getrandbits(100) | ||
| # when called with a 100-bits stop argument. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Allow ``random.getrandbits(0)`` to succeed and to return 0. |
Uh oh!
There was an error while loading. Please reload this page.