From 8be8949116e1812df5e329a18647ebdea7fb9c6c Mon Sep 17 00:00:00 2001 From: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:07:09 -0400 Subject: [PATCH] gh-91117: Ensure integer mod and pow operations use cached small ints (GH-31843) --- Lib/test/test_long.py | 42 +++++++++++++++++++ .../2022-03-13-08-23-17.bpo-46961.SgGCkG.rst | 1 + Objects/longobject.c | 2 + 3 files changed, 45 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-13-08-23-17.bpo-46961.SgGCkG.rst diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index e68dfb4c542..2de4526ff33 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1024,6 +1024,48 @@ class LongTest(unittest.TestCase): self.assertIs(a + b, 1) self.assertIs(c - a, 1) + @support.cpython_only + def test_pow_uses_cached_small_ints(self): + self.assertIs(pow(10, 3, 998), 2) + self.assertIs(10 ** 3 % 998, 2) + a, p, m = 10, 3, 998 + self.assertIs(a ** p % m, 2) + + self.assertIs(pow(2, 31, 2 ** 31 - 1), 1) + self.assertIs(2 ** 31 % (2 ** 31 - 1), 1) + a, p, m = 2, 31, 2 ** 31 - 1 + self.assertIs(a ** p % m, 1) + + self.assertIs(pow(2, 100, 2**100 - 3), 3) + self.assertIs(2 ** 100 % (2 ** 100 - 3), 3) + a, p, m = 2, 100, 2**100 - 3 + self.assertIs(a ** p % m, 3) + + @support.cpython_only + def test_divmod_uses_cached_small_ints(self): + big = 10 ** 100 + + self.assertIs((big + 1) % big, 1) + self.assertIs((big + 1) // big, 1) + self.assertIs(big // (big // 2), 2) + self.assertIs(big // (big // -4), -4) + + q, r = divmod(2 * big + 3, big) + self.assertIs(q, 2) + self.assertIs(r, 3) + + q, r = divmod(-4 * big + 100, big) + self.assertIs(q, -4) + self.assertIs(r, 100) + + q, r = divmod(3 * (-big) - 1, -big) + self.assertIs(q, 3) + self.assertIs(r, -1) + + q, r = divmod(3 * big - 1, -big) + self.assertIs(q, -3) + self.assertIs(r, -1) + def test_small_ints(self): for i in range(-5, 257): self.assertIs(i, i + 0) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-13-08-23-17.bpo-46961.SgGCkG.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-13-08-23-17.bpo-46961.SgGCkG.rst new file mode 100644 index 00000000000..8753377f6b8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-13-08-23-17.bpo-46961.SgGCkG.rst @@ -0,0 +1 @@ +Integer mod/remainder operations, including the three-argument form of :func:`pow`, now consistently return ints from the global small integer cache when applicable. diff --git a/Objects/longobject.c b/Objects/longobject.c index f85ef241a44..cc4aef31d74 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2679,6 +2679,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, } else { z = x_divrem(a, b, prem); + *prem = maybe_small_long(*prem); if (z == NULL) return -1; } @@ -2732,6 +2733,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) else { /* Slow path using divrem. */ Py_XDECREF(x_divrem(a, b, prem)); + *prem = maybe_small_long(*prem); if (*prem == NULL) return -1; }