[Python-checkins] gh-91117: Ensure integer mod and pow operations use cached small ints (GH-31843)

sweeneyde webhook-mailer at python.org
Mon Apr 11 16:07:19 EDT 2022


https://github.com/python/cpython/commit/8be8949116e1812df5e329a18647ebdea7fb9c6c
commit: 8be8949116e1812df5e329a18647ebdea7fb9c6c
branch: main
author: Dennis Sweeney <36520290+sweeneyde at users.noreply.github.com>
committer: sweeneyde <36520290+sweeneyde at users.noreply.github.com>
date: 2022-04-11T16:07:09-04:00
summary:

gh-91117: Ensure integer mod and pow operations use cached small ints (GH-31843)

files:
A Misc/NEWS.d/next/Core and Builtins/2022-03-13-08-23-17.bpo-46961.SgGCkG.rst
M Lib/test/test_long.py
M Objects/longobject.c

diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index e68dfb4c542ea..2de4526ff33fd 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -1024,6 +1024,48 @@ def test_small_ints_in_huge_calculation(self):
         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 0000000000000..8753377f6b8ed
--- /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 f85ef241a445d..cc4aef31d743c 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;
     }



More information about the Python-checkins mailing list