Index: Lib/test/test_long.py =================================================================== --- Lib/test/test_long.py (revision 61624) +++ Lib/test/test_long.py (working copy) @@ -552,6 +552,24 @@ self.assertRaises(OverflowError, int, float('inf')) self.assertRaises(OverflowError, int, float('nan')) + def test_small_ints(self): + for i in range(-5, 257): + self.assertTrue(i is i + 0) + self.assertTrue(i is i * 1) + self.assertTrue(i is i - 0) + self.assertTrue(i is i // 1) + self.assertTrue(i is i & -1) + self.assertTrue(i is i | 0) + self.assertTrue(i is i ^ 0) + self.assertTrue(i is ~~i) + self.assertTrue(i is i**1) + self.assertTrue(i is int(str(i))) + self.assertTrue(i is i<<2>>2, str(i)) + # corner cases + i = 1 << 70 + self.assertTrue(i - i is 0) + self.assertTrue(0 * i is 0) + def test_main(): test_support.run_unittest(LongTest) Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 61624) +++ Objects/longobject.c (working copy) @@ -15,6 +15,11 @@ #ifndef NSMALLNEGINTS #define NSMALLNEGINTS 5 #endif + +#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : \ + (Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0])) +#define ABS(x) ((x) < 0 ? -(x) : (x)) + #if NSMALLNEGINTS + NSMALLPOSINTS > 0 /* Small integers are preallocated in this array so that they can be shared. @@ -44,11 +49,23 @@ return get_small_int(ival); \ } while(0) +static PyLongObject * +maybe_small_long(PyLongObject *v) +{ + if (v && ABS(Py_SIZE(v)) <= 1) { + int ival = MEDIUM_VALUE(v); + if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { + Py_DECREF(v); + return (PyLongObject *)get_small_int(ival); + } + } + return v; +} #else #define CHECK_SMALL_INT(ival) +#define maybe_small_long(val) (val) #endif -#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : (Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0])) /* If a freshly-allocated long is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ #define NEGATE(x) \ @@ -70,8 +87,6 @@ */ #define FIVEARY_CUTOFF 8 -#define ABS(x) ((x) < 0 ? -(x) : (x)) - #undef MIN #undef MAX #define MAX(x, y) ((x) < (y) ? (y) : (x)) @@ -1929,7 +1944,7 @@ goto onError; if (pend) *pend = str; - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); onError: Py_XDECREF(z); @@ -2018,7 +2033,7 @@ NEGATE(z); if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) NEGATE(*prem); - *pdiv = z; + *pdiv = maybe_small_long(z); return 0; } @@ -2275,7 +2290,7 @@ while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) ; if (i < 0) - return _PyLong_New(0); + return PyLong_FromLong(0); if (a->ob_digit[i] < b->ob_digit[i]) { sign = -1; { PyLongObject *temp = a; a = b; b = temp; } @@ -2528,7 +2543,7 @@ i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF; if (asize <= i) { if (asize == 0) - return _PyLong_New(0); + return PyLong_FromLong(0); else return x_mul(a, b); } @@ -3139,7 +3154,7 @@ if (x == NULL) return NULL; Py_SIZE(x) = -(Py_SIZE(x)); - return (PyObject *)x; + return (PyObject *)maybe_small_long(x); } static PyObject * @@ -3204,10 +3219,8 @@ } wordshift = shiftby / PyLong_SHIFT; newsize = ABS(Py_SIZE(a)) - wordshift; - if (newsize <= 0) { - z = _PyLong_New(0); - return (PyObject *)z; - } + if (newsize <= 0) + return PyLong_FromLong(0); loshift = shiftby % PyLong_SHIFT; hishift = PyLong_SHIFT - loshift; lomask = ((digit)1 << hishift) - 1; @@ -3226,7 +3239,7 @@ z = long_normalize(z); } rshift_error: - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); } @@ -3282,7 +3295,7 @@ assert(!accum); z = long_normalize(z); lshift_error: - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); } @@ -3388,7 +3401,7 @@ Py_DECREF(b); z = long_normalize(z); if (negz == 0) - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); v = long_invert(z); Py_DECREF(z); return v;