Python:有没有办法保持从int到long int的自动转换?

daw*_*awg 13 python performance integer long-integer

Python比其他脚本语言更强类型.例如,在Perl中:

perl -E '$c=5; $d="6"; say $c+$d'   #prints 11
Run Code Online (Sandbox Code Playgroud)

但是在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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

现在Python 将从一个int 自动推进,在这种情况下,它是64位长(OS X,python 2.6.1)到python long int,它具有任意精度.即使类型不同,它们也是相似的,Python允许使用通常的数字运算符.通常这很有帮助.例如,它有助于平滑32位和64位之间的差异.

从转换int到long是单向的:

>>> type((maxint+2)-2)
<type 'long'>
Run Code Online (Sandbox Code Playgroud)

转换完成后,该变量的所有操作现在都以任意精度完成.任意精度操作比原生int操作慢几个数量级.在我正在处理的脚本上,我会有一些执行是快速的,其他因为这个延长到几个小时.考虑:

>>> print maxint**maxint        # execution so long it is essentially a crash
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:有没有办法打败或不允许将Python自动推广int到Python long?

编辑,跟进:

我收到了几条评论,形式为'为什么你想要C风格溢出行为?' 问题是这段特殊的代码在C和Perl(带use int)中的32位上运行正常,带有C的溢出行为.尝试将此代码移植到Python失败了.Python的不同溢出行为最终成为问题的(部分).代码中有许多不同的习语(C,Perl,某些python)混合在一起(和那些评论混合在一起),所以它具有挑战性.

基本上,正在进行的图像分析是基于盘的高通滤波器以执行类似的图像比较.部分高通滤波器具有两个大多项式的基于整数的乘法.溢出本质上是一种"不关心,它很大......"的逻辑,因此结果与基于C的溢出一样.因此,使用具有O(n 2)时间的Horner规则是一种浪费,因为较大的多项式只是"大" - 粗略正义形式的carot-top饱和算法.

将基于循环的多项式乘法更改为FFT的形式可能要快得多.对于Horner的规则多项式乘法,FFT以接近线性的时间与O(n 2)运行.从光盘到内存也将加速这一进程.图像并不是非常大,但原始代码是在它们被认为是"巨大!!!"的时候编写的.代码所有者还没准备好丢弃他心爱的代码,所以我们会看到.他的'正确答案'可能只是保留Perl或C,如果他想要那个代码.

谢谢你的回答.我不知道Python的十进制模块,这似乎最接近我的要求 - 即使在这种情况下还有其他问题需要解决!

Cra*_*een 5

如果您希望算术溢出在例如32位内溢出,您可以使用例如numpy.uint32.

发生溢出时会发出警告.

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

我测试了它的速度:

>\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
Run Code Online (Sandbox Code Playgroud)

这对速度来说并不好看.

  • 你在每个循环中调用了四次构造函数,这将是非常昂贵的.相反,你应该自己缓存`uint32`对象. (3认同)
  • 它会比通常的整数运算慢得多,因为 numpy 对每个项目的处理开销非常大 (2认同)

the*_*olf 5

所以你想扔掉 One True Way 并在溢出时复古。你傻。

C/C++/C#/Java 风格的溢出没有什么好处。它不会可靠地引发错误条件。对于 C 和 C99,它是 ANSI 和 POSIX 中的“未定义行为”(C++ 要求取模返回),并且是已知的安全风险。你为什么要这个?

无缝溢出到long的Python方法是更好的方法。我相信这与 Perl 6 所采用的行为相同。

您可以使用Decimal 模块获得更多有限溢出:

>>> 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
Run Code Online (Sandbox Code Playgroud)

您可以使用 Decimal 类设置精度和边界条件,并且溢出几乎是立即的。你可以设置你的陷阱。您可以设置最大值和最小值。真的 - 它如何变得比这更好?(老实说,我不知道相对速度,但我怀疑它比 numby 快,但显然比本地整数慢......)

对于图像处理的特定问题,这听起来像是考虑某种形式的饱和度算术的自然应用。您还可能会考虑,如果您在 32 位算术上出现溢出,请在明显情况下沿途检查操作数:pow、**、*。您可能会考虑重载运算符并检查您不想要的条件。

如果 Decimal、saturation 或重载运算符不起作用 -您可以编写扩展. 如果你想扔掉溢出的 Python 方式去复古,天堂会帮助你......