Lelouch Lamperouge
Lelouch Lamperouge

Reputation: 8421

integer gets promoted to long but not vice versa in Python. Why?

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

Answers (3)

Matt Fenwick
Matt Fenwick

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 longs yield more longs 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 returns NotImplemented, 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

philofinfinitejest
philofinfinitejest

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

Martin Beckett
Martin Beckett

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

Related Questions