Я хотел бы представить значение в виде 64-битного подписанного long
, так что значения больше (2 ** 63) -1 представлены как отрицательные, однако Python long
имеет бесконечную точность. Есть ли "быстрый" способ достичь этого?
Тип Python long vs C 'long long'
Ответ 1
Вы можете использовать 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
, вы можете сделать что-то вроде этого ( note: только 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
.
Ответ 2
Можете ли вы использовать 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 может быть больше, чем другие решения, но если вы проводите численный анализ, вы оцените его.
Ответ 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)
...
но это не особенно "быстро" реализовать.
Ответ 4
Посмотрите на модуль ctypes, он используется для вызова иностранных библиотек DLL/библиотек из python. Существуют некоторые типы данных, которые соответствуют типам C, например
класс c_longlong