Python: Есть ли способ сохранить автоматическое преобразование из int в long int из происходящего?

Python более строго типизирован, чем другие языки сценариев. Например, в Perl:

perl -E '$c=5; $d="6"; say $c+$d'   #prints 11

Но в Python:

>>> c="6"
>>> d=5
>>> print c+d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

Perl проверит строку и преобразует ее в число, а операторы + - / * ** работают, как вы ожидаете, с числом. PHP похож.

Python использует + для конкатенации строк, поэтому попытка операции c+d не выполняется, потому что c является строкой, d и int. Python имеет более сильное чувство числовые типы, чем Perl. Хорошо. Я могу справиться с этим.

Но рассмотрим:

>>> from sys import maxint
>>> type(maxint)
<type 'int'>
>>> print maxint
9223372036854775807
>>> type(maxint+2)
<type 'long'>
>>> print maxint+2
9223372036854775809
>>> type((maxint+2)+maxint)
<type 'long'>
>>> print ((maxint+2)+maxint)
18446744073709551616

Теперь Python будет autopromote из int, который в этом случае является 64-битным (OS X, python 2.6.1) python long int, который имеет произвольную точность. Несмотря на то, что типы не совпадают, они похожи, и Python позволяет использовать обычные числовые операторы. Обычно это полезно. Это полезно при сглаживании различий между 32-битным и 64-битным, например.

Преобразование из int в long является одним из способов:

>>> type((maxint+2)-2)
<type 'long'>

После завершения преобразования все операции над этой переменной выполняются произвольной точностью. Операции произвольной точности на несколько порядков медленнее, чем нативные операции int. На script, над которым я работаю, я бы выполнил какое-то исполнение, и это из-за этого ускорилось. Рассмотрим:

>>> print maxint**maxint        # execution so long it is essentially a crash

Итак, мой вопрос: есть ли способ победить или не разрешить авто-продвижение Python int на Python long?

Изменить, следить:

Я получил несколько комментариев в форме: "Почему бы вам не хотеть иметь поведение переполнения стиля С?" Проблема заключалась в том, что этот фрагмент кода работал нормально на 32 битах в C и Perl (с use int) с поведением C переполнения. Произошла неудачная попытка перенести этот код на Python. Различное поведение переполнения Python оказывается (частью) проблемы. В коде много разных этих идиом (C, Perl, некоторые python), смешанные в (и эти комментарии смешались), поэтому это было сложно.

По существу, выполняемый анализ изображения представляет собой фильтр верхних частот на основе диска для выполнения аналогичного сравнения изображений. Часть фильтра верхних частот имеет целочисленное умножение двух больших многочленов. Переполнение было, по сути, логикой "не заботьтесь, это большая...", поэтому результат был таким же, как предполагалось, с переполнением на основе C. Таким образом, использование правила Хорнера с временем O (n 2) было отходом, поскольку большие многочлены были бы просто "большими" - арифметикой грубой справедливости арифметики насыщения каротином.

Изменение многочленного умножения на основе цикла на форму БПФ, вероятно, значительно быстрее. FFT работает в близком к линейному времени vs O (n 2) для многочлена многочлена Horner. Переход с диска на встроенную память также ускорит это. Изображения не очень большие, но исходный код был написан в то время, когда они считались "огромными!!!" Владелец кода не совсем готов уничтожить его любимый код, так что посмотрим. "Правильный ответ" для него, вероятно, это просто держать Perl или C, если он хочет этот код.

Спасибо за ответы. Я не знал о десятичном модуле Python, и это, казалось, было самым близким к тому, что я просил - даже если в этом случае есть другие проблемы!

Ответ 1

Итак, вы хотите выбрасывать One True Way и идти ретро на переполнения. Ты глупый.

Нет хорошего отношения к переполнению C/С++/С#/Java. Он не уверенно поднимает условие ошибки. Для C и C99 это "поведение undefined" в ANSI и POSIX (С++ требует возврата по модулю), и это известный риск безопасности. Почему вы хотите этого?

Метод Python легко переполняется дольше, это лучший способ. Я считаю, что такое же поведение адаптируется Perl 6.

Вы можете использовать Decimal module, чтобы получить более конечные переполнения:

>>> from decimal import *
>>> from sys import maxint
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, capitals=1,
flags=[], traps=[DivisionByZero, Overflow, InvalidOperation])

>>> d=Decimal(maxint)
>>> d
Decimal('9223372036854775807')
>>> e=Decimal(maxint)
>>> f=d**e
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/decimal.py", line 2225, in __pow__
    ans = ans._fix(context)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/decimal.py", line 1589, in _fix
    return context._raise_error(Overflow, 'above Emax', self._sign)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/decimal.py", line 3680, in _raise_error
    raise error(explanation)
decimal.Overflow: above Emax

Вы можете установить прецизионные и граничные условия с десятичными классами, а переполнение почти мгновенно. Вы можете установить, что вы ловушки. Вы можете установить максимальный и минимальный. Действительно - как это получается лучше, чем это? (Я не знаю об относительной скорости, чтобы быть честным, но я подозреваю, что это быстрее, чем numby, но медленнее, чем native ints, очевидно...)

Для вашей конкретной проблемы обработки изображений это звучит как естественное приложение для рассмотрения некоторой формы арифметики насыщения. Вы также можете подумать, если у вас есть переполнение по 32 арифметическим, проверьте операнды по пути в очевидных случаях: pow, **, *. Вы можете рассмотреть перегруженные операторы и проверить условия, которые вы не хотите.

Если десятичные, насыщенные или перегруженные операторы не работают - вы можете написать расширение. Небеса помогут вам, если вы хотите выкинуть путь переполнения Python, чтобы перейти к ретро...

Ответ 2

Если вы хотите, чтобы арифметические переполнения переполнялись в пределах, например. 32 бита, вы можете использовать, например. numpy.uint32.

Это дает вам предупреждение, когда происходит переполнение.

>>> import numpy
>>> numpy.uint32(2**32-3) + numpy.uint32(5)
Warning: overflow encountered in ulong_scalars
2

Я тестировал свою скорость, хотя:

>\python26\python.exe -m timeit "2**16 + 2**2"
1000000 loops, best of 3: 0.118 usec per loop

>\python26\python.exe -m timeit "2**67 + 2**65"
1000000 loops, best of 3: 0.234 usec per loop

>\python26\python.exe -m timeit -s "import numpy; numpy.seterr('ignore')" "numpy.uint32(2)**numpy.uint32(67) + numpy.uint32(2)**numpy.uint32(65)"
10000 loops, best of 3: 34.7 usec per loop

Это не выглядит хорошо для скорости.

Ответ 3

Int vs long - историческое наследие - в python 3 каждый int является "длинным". Если ваша скорость script ограничена int-вычислением, вероятно, что вы делаете это неправильно.

Чтобы дать вам правильный ответ, нам нужна дополнительная информация о том, что вы пытаетесь сделать.

Ответ 4

Вы можете заставить свои значения вернуться к нормальному int, если вы иногда включаете num = int(num) в свой алгоритм. Если значение длинное, но вписывается в собственный int, оно уменьшает значение до int. Если значение не вписывается в собственный int, оно останется длинным.

Ответ 5

Я не знаю, будет ли это быстрее, но вы можете использовать массивы numpy одного элемента вместо ints.

Если конкретный расчет, который вас интересует, представляет собой целочисленное возведение в степень, то есть некоторые выводы, которые мы можем сделать:

def smart_pow(mantissa, exponent, limit=int(math.ceil(math.log(sys.maxint)/math.log(2)))):
    if mantissa in (0, 1):
        return mantissa
    if exponent > limit:
        if mantissa == -1: 
            return -1 if exponent&1 else 1
        if mantissa > 1:
            return sys.maxint
        else: 
            return (-1-sys.maxint) if exponent&1 else sys.maxint
    else: # this *might* overflow, but at least it won't take long
        return mantissa ** exponent

Ответ 6

Хорошо, если вы не заботитесь о точности, вы можете использовать все свои математические операции по модулю maxint.