mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-36887: add math.isqrt (GH-13244)
* Add math.isqrt function computing the integer square root. * Code cleanup: remove redundant comments, rename some variables. * Tighten up code a bit more; use Py_XDECREF to simplify error handling. * Update Modules/mathmodule.c Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> * Update Modules/mathmodule.c Use real argument clinic type instead of an alias Co-Authored-By: Serhiy Storchaka <storchaka@gmail.com> * Add proof sketch * Updates from review. * Correct and expand documentation. * Fix bad reference handling on error; make some variables block-local; other tidying. * Style and consistency fixes. * Add missing error check; don't try to DECREF a NULL a * Simplify some error returns. * Another two test cases: - clarify that floats are rejected even if they happen to be squares of small integers - TypeError beats ValueError for a negative float * Documentation and markup improvements; thanks Serhiy for the suggestions! * Cleaner Misc/NEWS entry wording. * Clean up (with one fix) to the algorithm explanation and proof.
This commit is contained in:
parent
410759fba8
commit
73934b9da0
6 changed files with 343 additions and 1 deletions
|
@ -912,6 +912,57 @@ class MathTests(unittest.TestCase):
|
|||
self.assertEqual(math.dist(p, q), 5*scale)
|
||||
self.assertEqual(math.dist(q, p), 5*scale)
|
||||
|
||||
def testIsqrt(self):
|
||||
# Test a variety of inputs, large and small.
|
||||
test_values = (
|
||||
list(range(1000))
|
||||
+ list(range(10**6 - 1000, 10**6 + 1000))
|
||||
+ [3**9999, 10**5001]
|
||||
)
|
||||
|
||||
for value in test_values:
|
||||
with self.subTest(value=value):
|
||||
s = math.isqrt(value)
|
||||
self.assertIs(type(s), int)
|
||||
self.assertLessEqual(s*s, value)
|
||||
self.assertLess(value, (s+1)*(s+1))
|
||||
|
||||
# Negative values
|
||||
with self.assertRaises(ValueError):
|
||||
math.isqrt(-1)
|
||||
|
||||
# Integer-like things
|
||||
s = math.isqrt(True)
|
||||
self.assertIs(type(s), int)
|
||||
self.assertEqual(s, 1)
|
||||
|
||||
s = math.isqrt(False)
|
||||
self.assertIs(type(s), int)
|
||||
self.assertEqual(s, 0)
|
||||
|
||||
class IntegerLike(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __index__(self):
|
||||
return self.value
|
||||
|
||||
s = math.isqrt(IntegerLike(1729))
|
||||
self.assertIs(type(s), int)
|
||||
self.assertEqual(s, 41)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
math.isqrt(IntegerLike(-3))
|
||||
|
||||
# Non-integer-like things
|
||||
bad_values = [
|
||||
3.5, "a string", decimal.Decimal("3.5"), 3.5j,
|
||||
100.0, -4.0,
|
||||
]
|
||||
for value in bad_values:
|
||||
with self.subTest(value=value):
|
||||
with self.assertRaises(TypeError):
|
||||
math.isqrt(value)
|
||||
|
||||
def testLdexp(self):
|
||||
self.assertRaises(TypeError, math.ldexp)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue