2009-11-19 32 views
11

Me gustaría representar un valor como 64bit firmado long, de modo que los valores mayores que (2 ** 63) -1 se representan como negativos, sin embargo, Python long tiene una precisión infinita. ¿Hay una manera "rápida" de lograr esto?Python tipo long vs C 'long long'

Respuesta

13

usted podría utilizar 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 

Esto es realmente única una opción si sepa con seguridad que un signed long long tendrá una anchura de 64 bits en la (s) máquina (s) de destino.

Editar:jorendorff's idea de definir una clase de números de 64 bits es atractivo. Lo ideal es minimizar el número de creaciones de clases explícitas.

Usando c_longlong, se podría hacer algo como esto (nota:! 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)) 

    ... 

De esta manera el resultado de ll(2 ** 63) - 1 será de hecho 9223372036854775807. Sin embargo, esta construcción puede dar como resultado una penalización en el rendimiento, por lo que dependiendo de lo que quieras hacer exactamente, definir una clase como la anterior no puede valer la pena. En caso de duda, use timeit.

3

Lo más rápido es, probablemente, para truncar el resultado de 64 bits de sí mismo:

def to_int64(n): 
    n = n & ((1 << 64) - 1) 
    if n > (1 << 63) - 1: 
     n -= 1 << 64 
    return n 

Por supuesto, puede definir su propio tipo numérico que hace automáticamente cada vez que lo hace cualquier tipo de operación aritmética:

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) 

    ... 

pero eso no es particularmente "rápido" de implementar.

1

Eche un vistazo al módulo ctypes, se usa para llamar a bibliotecas/DLL extranjeras de python. Hay un algunos tipos de datos que corresponden a los tipos C, por ejemplo

c_longlong clase

10

¿Se puede usar numpy? Tiene un tipo int64 que hace exactamente lo que quieres.

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 

Es transparente para los usuarios, a diferencia del ejemplo ctypes, y está codificado en C por lo que será más rápido que rodar su propia clase en Python. Numpy puede ser más grande que las otras soluciones, pero si está haciendo un análisis numérico, apreciará tenerlo.