Python中的long与C语言的'long long'对比
我想把一个值表示成64位的有符号long
类型,这样如果这个值大于(2**63)-1
,它就会被当作负数来处理。不过,Python的long
类型可以表示任意大小的数字,没什么限制。请问有没有什么“快速”的方法可以做到这一点呢?
4 个回答
3
最快的方法可能就是自己把结果截断到64位:
def to_int64(n):
n = n & ((1 << 64) - 1)
if n > (1 << 63) - 1:
n -= 1 << 64
return n
当然,你也可以定义一个自己的数字类型,这样每次进行任何算术运算时,它都会自动处理这个截断:
class Int64:
def __init__(self, n):
if isinstance(n, Int64):
n = n.val
self.val = to_int64(n)
def __add__(self, other):
return Int64(self.val + other)
def __radd__(self, other):
return Int64(other + self.val)
def __sub__(self, other):
return Int64(self.val - other)
...
不过,这样做实现起来并不是特别“快”。
13
你能用numpy吗?它有一种叫做int64的数据类型,正好符合你的需求。
In [1]: import numpy
In [2]: numpy.int64(2**63-1)
Out[2]: 9223372036854775807
In [3]: numpy.int64(2**63-1)+1
Out[3]: -9223372036854775808
对用户来说,这个用法很简单,不像ctypes的例子那么复杂。而且它是用C语言写的,所以运行速度会比你自己在Python里写的类快。虽然numpy可能比其他解决方案要大一些,但如果你在做数字分析的话,你会觉得它非常有用。
14
你可以使用 ctypes.c_longlong
:
>>> from ctypes import c_longlong as ll
>>> ll(2 ** 63 - 1)
c_longlong(9223372036854775807L)
>>> ll(2 ** 63)
c_longlong(-9223372036854775808L)
>>> ll(2 ** 63).value
-9223372036854775808L
这其实仅仅是在你确定目标机器上的 signed long long
是64位的情况下才适用。
编辑: jorendorff的想法是定义一个64位数字的类,这个主意很不错。理想情况下,你希望尽量减少显式创建类的次数。
使用 c_longlong
,你可以这样做(注意:仅适用于Python 3.x!):
from ctypes import c_longlong
class ll(int):
def __new__(cls, n):
return int.__new__(cls, c_longlong(n).value)
def __add__(self, other):
return ll(super().__add__(other))
def __radd__(self, other):
return ll(other.__add__(self))
def __sub__(self, other):
return ll(super().__sub__(other))
def __rsub__(self, other):
return ll(other.__sub__(self))
...
这样,ll(2 ** 63) - 1
的结果确实会是 9223372036854775807
。不过,这种写法可能会影响性能,所以根据你具体想做的事情,像上面那样定义一个类可能不太值得。如果不确定,可以使用 timeit
来测试一下。