Python:有没有办法阻止从 int 到 long int 的自动转换发生?

发布于 2024-10-06 11:52:28 字数 790 浏览 10 评论 0原文

考虑这个例子:

>>> 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 将从 intautopromote code>,在本例中是一个 64 位整数值(OS X,python 2.6.1)到任意精度的 python long 整数。尽管类型不相同,但它们很相似,并且 Python 允许使用常用的数字运算符。通常这很有用,例如能够在 32 位机器上使用需要 64 位值的代码。

然而,任意精度运算比本机 int 运算慢得多。例如:

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

有没有办法阻止或禁止将 Python int 自动升级为 Python long

Consider the example:

>>> 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 will autopromote from an int, which in this case is a 64 bit integer value (OS X, python 2.6.1) to a python long integer which is of arbitrary precision. Even though the types are not the same, they are similar and Python allows the usual numeric operators to be used. Usually this is helpful, for example to be able to use code that expects 64-bit values on a 32-bit machine.

However, the arbitrary precision operations are vastly slower than the native int operations. For example:

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

Is there a way to defeat or disallow the auto-promotion of a Python int to a Python long?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

少女情怀诗 2024-10-13 11:52:28

所以你想抛弃“唯一正确的方法”并在溢出问题上复古。愚蠢的你。

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

您可以使用 Decimal 类设置精度和边界条件,并且溢出几乎是立即的。您可以设置陷阱的内容。您可以设置最大值和最小值。真的——还有什么比这更好的呢? (说实话,我不知道相对速度,但我怀疑它比 numby 更快,但显然比本机整数慢......)

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

如果小数、饱和或重载运算符不起作用 - 您可以编写扩展。如果你想抛弃Python的溢出方式来复古的话,天堂会帮助你的......

So you want to throw out the One True Way and go retro on overflows. Silly you.

There is no good upside to the C / C++ / C# / Java style of overflow. It does not reliably raise an error condition. For C and C99 it is "undefined behavior" in ANSI and POSIX (C++ mandates modulo return) and it is a known security risk. Why do you want this?

The Python method of seamlessly overflowing to a long is the better way. I believe this is the same behavior being adapted by Perl 6.

You can use the Decimal module to get more finite overflows:

>>> 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

You can set your precision and boundary conditions with Decimal classes and the overflow is nearly immediate. You can set what you trap for. You can set your max and min. Really -- How does it get better than this? (I don't know about relative speed to be honest, but I suspect it is faster than numby but slower than native ints obviously...)

For your specific issue of image processing, this sounds like a natural application to consider some form of saturation arithmetic. You also might consider, if you are having overflows on 32 arithmetic, check operands along the way on obvious cases: pow, **, *. You might consider overloaded operators and check for the conditions you don't want.

If Decimal, saturation, or overloaded operators don't work -- you can write an extension. Heaven help you if you want to throw out the Python way of overflow to go retro...

寂寞花火° 2024-10-13 11:52:28

如果您希望算术溢出在例如 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

它看起来速度不太好。

If you want arithmetic overflows to overflow within e.g. 32 bits, you could use e.g. numpy.uint32.

That gives you a warning when an overflow occurs.

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

I tested its speed though:

>\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

It's not looking good for speed.

放飞的风筝 2024-10-13 11:52:28

如果您偶尔在算法中包含 num = int(num),则可以强制您的值返回正常的 int。如果该值很长但适合本机 int,它将降级为 int。如果该值不适合本机 int,它将保留为 long。

You can force your values to return to normal ints if you include an num = int(num) occasionally in your algorithm. If the value is long but fits in a native int, it will demote down to int. If the value doesn't fit in a native int, it will remain a long.

就是爱搞怪 2024-10-13 11:52:28

Int 与 long 是一个历史遗产 - 在 python 3 中,每个 int 都是一个“long”。如果你的脚本速度受到 int 计算的限制,那么你可能做错了。

为了给您一个正确的答案,我们需要更多关于您想要做什么的信息。

Int vs long is an historical legacy - in python 3, every int is a "long". If your script speed is limited by int computation, it is likely that you are doing it wrong.

To give you a proper answer, we need more information on what are you trying to do.

∝单色的世界 2024-10-13 11:52:28

好吧,如果您不关心准确性,您可以将所有数学运算对 maxint 取模。

Well, if you don't care about accuracy you could all of your math ops modulo maxint.

下雨或天晴 2024-10-13 11:52:28

我不知道它是否会更快,但您可以使用一个元素的 numpy 数组而不是整数。

如果你关心的具体计算是整数求幂,那么我们可以得出一些推论:

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

I don't know if it would be faster, neccesarily, but you could use numpy arrays of one element instead of ints.

If the specific calculation you are concerned about is integer exponentiation, then there are some inferences we can draw:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文