diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index f336d49fa4f008..c206c9e02a9fbc 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -1693,5 +1693,22 @@ class MyInt(int): # GH-117195 -- This shouldn't crash object.__sizeof__(1) + def test_hash(self): + # gh-136599 + self.assertEqual(hash(-1), -2) + self.assertEqual(hash(0), 0) + self.assertEqual(hash(10), 10) + + self.assertEqual(hash(sys.hash_info.modulus - 2), sys.hash_info.modulus - 2) + self.assertEqual(hash(sys.hash_info.modulus - 1), sys.hash_info.modulus - 1) + self.assertEqual(hash(sys.hash_info.modulus), 0) + self.assertEqual(hash(sys.hash_info.modulus + 1), 1) + + self.assertEqual(hash(-sys.hash_info.modulus - 2), -2) + self.assertEqual(hash(-sys.hash_info.modulus - 1), -2) + self.assertEqual(hash(-sys.hash_info.modulus), 0) + self.assertEqual(hash(-sys.hash_info.modulus + 1), - (sys.hash_info.modulus - 1)) + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-13-21-21-17.gh-issue-136599.sLhm2O.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-13-21-21-17.gh-issue-136599.sLhm2O.rst new file mode 100644 index 00000000000000..9bcb13f9e20caf --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-13-21-21-17.gh-issue-136599.sLhm2O.rst @@ -0,0 +1 @@ +Improve performance of :class:`int` hash calculations. diff --git a/Objects/longobject.c b/Objects/longobject.c index 581db10b54ab57..e5e36cdb01b0eb 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3676,7 +3676,20 @@ long_hash(PyObject *obj) } i = _PyLong_DigitCount(v); sign = _PyLong_NonCompactSign(v); - x = 0; + + // unroll first two digits +#if ( PyHASH_BITS > PyLong_SHIFT ) + assert(i>=2); + --i; + x = v->long_value.ob_digit[i]; + assert(x < _PyHASH_MODULUS); +#endif +#if ( PyHASH_BITS > (2 * PyLong_SHIFT) ) + --i; + x = ((x << PyLong_SHIFT)); + x += v->long_value.ob_digit[i]; + assert(x < _PyHASH_MODULUS); +#endif while (--i >= 0) { /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we want to compute x * 2**PyLong_SHIFT + v->long_value.ob_digit[i] modulo