Reputation: 8421
When the value of an number goes beyond the integer
range, python promotes it to a long
. But when the value comes back to the integer range, why doesn't it get demoted to an int
?
>>> i=2147483647
>>> type(i)
<type 'int'>
>>> i = i + 1
>>> type(i)
<type 'long'>
>>> i = i - 10
>>> type(i)
<type 'long'>
>>> i
2147483638L
>>>
Upvotes: 4
Views: 239
Reputation: 49105
From the python source (in file Objects/longobject.c):
static PyLongObject *
x_add(PyLongObject *a, PyLongObject *b)
{
Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size);
PyLongObject *z;
int i;
digit carry = 0;
/* Ensure a is the larger of the two: */
if (size_a < size_b) {
{ PyLongObject *temp = a; a = b; b = temp; }
{ Py_ssize_t size_temp = size_a;
size_a = size_b;
size_b = size_temp; }
}
z = _PyLong_New(size_a+1);
if (z == NULL)
return NULL;
for (i = 0; i < size_b; ++i) {
carry += a->ob_digit[i] + b->ob_digit[i];
z->ob_digit[i] = carry & MASK;
carry >>= SHIFT;
}
for (; i < size_a; ++i) {
carry += a->ob_digit[i];
z->ob_digit[i] = carry & MASK;
carry >>= SHIFT;
}
z->ob_digit[i] = carry;
return long_normalize(z);
}
/* Subtract the absolute values of two integers. */
static PyLongObject *
x_sub(PyLongObject *a, PyLongObject *b)
{
Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size);
PyLongObject *z;
Py_ssize_t i;
int sign = 1;
digit borrow = 0;
/* Ensure a is the larger of the two: */
if (size_a < size_b) {
sign = -1;
{ PyLongObject *temp = a; a = b; b = temp; }
{ Py_ssize_t size_temp = size_a;
size_a = size_b;
size_b = size_temp; }
}
else if (size_a == size_b) {
/* Find highest digit where a and b differ: */
i = size_a;
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
;
if (i < 0)
return _PyLong_New(0);
if (a->ob_digit[i] < b->ob_digit[i]) {
sign = -1;
{ PyLongObject *temp = a; a = b; b = temp; }
}
size_a = size_b = i+1;
}
z = _PyLong_New(size_a);
if (z == NULL)
return NULL;
for (i = 0; i < size_b; ++i) {
/* The following assumes unsigned arithmetic
works module 2**N for some N>SHIFT. */
borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
z->ob_digit[i] = borrow & MASK;
borrow >>= SHIFT;
borrow &= 1; /* Keep only one sign bit */
}
for (; i < size_a; ++i) {
borrow = a->ob_digit[i] - borrow;
z->ob_digit[i] = borrow & MASK;
borrow >>= SHIFT;
borrow &= 1; /* Keep only one sign bit */
}
assert(borrow == 0);
if (sign < 0)
z->ob_size = -(z->ob_size);
return long_normalize(z);
}
Note that the return types of both procedures are PyLongObject *
.
What this shows is that addition and subtraction of long
s yield more long
s in python, regardless of whether the values could fit in ints.
Example:
>>> 3L + 4L
7L
And here are python's coercion rules, specifically:
For objects x and y, first
x.__add__(y)
is tried. If this is not implemented or returnsNotImplemented
,y.__add__(x)
is tried. If this is also not implemented or returns NotImplemented, a TypeError exception is raised.
So doing i - 10
, where i
is a long
, results in another long
.
Upvotes: 1
Reputation: 4047
As further evidence of the python development team's thinking on int vs long, in python 3 int and long are unified.
http://docs.python.org/release/3.0.1/whatsnew/3.0.html#integers
Upvotes: 1
Reputation: 96147
Promoting an int
to a long
doesn't lose any information and is necessary to store bigger numbers.
Demoting isn't necessary and wouldn't have any real advantage - other than saving 4bytes of memory - which isn't really a priority in an interpreted language.
Upvotes: 4