Skip to content

Commit 476cfa4

Browse files
taegyunkimclaude
andcommitted
Fix GCD and test_int for 60-bit PyLong digits
Two fixes for 60-bit digit support: 1. Fix _PyLong_GCD() to return non-negative results for 60-bit digits - The 60-bit path in the "simple" case was skipping long_abs() calls - This caused gcd(-1, 0) to return -1 instead of 1 - Added long_abs() calls for both inputs before the GCD algorithm - Fixes test_math::testGcd and all test_pow failures (3,075 cases) 2. Adjust test_pylong_int_divmod_crash for larger digit sizes - The test uses k=10,000 to ensure _pylong.int_divmod() is called - With 60-bit digits, the threshold is higher (need more bits/digits) - Scale k based on bits_per_digit: k = 10,000 * (bits_per_digit // 30) - For 60-bit: k=20,000, for 30-bit: k=10,000, for 15-bit: k=5,000 All previously failing tests now pass: - test_decimal: OK - test_fractions: OK - test_int: OK (was 1 failure) - test_math: OK (was 7 failures) - test_numeric_tower: OK - test_pow: OK (was 3,075 failures) - test_statistics: OK Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 671323d commit 476cfa4

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

Lib/test/test_int.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,9 @@ def test_pylong_int_divmod_crash(self):
784784
# Regression test for https://github.com/python/cpython/issues/142554.
785785
bad_int_divmod = lambda a, b: (1,)
786786
# 'k' chosen such that divmod(2**(2*k), 2**k) uses _pylong.int_divmod()
787-
k = 10_000
787+
# Scale k based on digit size: larger digits need larger k to reach the threshold
788+
bits_per_digit = sys.int_info.bits_per_digit
789+
k = 10_000 * (bits_per_digit // 30)
788790
a, b = (1 << (2 * k)), (1 << k)
789791
with mock.patch.object(_pylong, "int_divmod", wraps=bad_int_divmod):
790792
msg = r"tuple of length 2 is required from int_divmod\(\)"

Objects/longobject.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5899,6 +5899,22 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg)
58995899
y = PyLong_AsLongLong((PyObject *)b);
59005900
#else
59015901
/* For very large digits (like 60-bit), fall back to general algorithm */
5902+
/* First take absolute values, since GCD must be non-negative */
5903+
PyLongObject *a_abs = long_abs(a);
5904+
Py_DECREF(a);
5905+
if (a_abs == NULL) {
5906+
Py_DECREF(b);
5907+
return NULL;
5908+
}
5909+
PyLongObject *b_abs = long_abs(b);
5910+
Py_DECREF(b);
5911+
if (b_abs == NULL) {
5912+
Py_DECREF(a_abs);
5913+
return NULL;
5914+
}
5915+
a = a_abs;
5916+
b = b_abs;
5917+
59025918
/* Use the Euclidean GCD algorithm directly on PyLong objects */
59035919
while (!_PyLong_IsZero(b)) {
59045920
PyLongObject *temp;

0 commit comments

Comments
 (0)