summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2019-05-18 11:29:50 (GMT)
committerGitHub <noreply@github.com>2019-05-18 11:29:50 (GMT)
commit73934b9da07daefb203e7d26089e7486a1ce4fdf (patch)
tree6d5f9d2f8bd86dbd219685a3e6124af44a158811 /Lib
parent410759fba80aded5247b693c60745aa16906f3bb (diff)
downloadcpython-73934b9da07daefb203e7d26089e7486a1ce4fdf.zip
cpython-73934b9da07daefb203e7d26089e7486a1ce4fdf.tar.gz
cpython-73934b9da07daefb203e7d26089e7486a1ce4fdf.tar.bz2
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.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_math.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index cb05dee..a11a344 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -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)