2009-11-19 18 views
11

Vorrei rappresentare un valore come 64bit firmato long, tale che i valori superiori a (2 ** 63) -1 sono rappresentati come negativi, tuttavia Python long ha una precisione infinita. C'è un modo 'veloce' per me per raggiungere questo obiettivo?Python type long vs C 'long long'

risposta

13

si potrebbe usare 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 

questo è davvero solo un'opzione se Sappiamo per certo che uno signed long long sarà largo 64 bit sui computer di destinazione.

Modifica:jorendorff's idea di definizione di una classe per i numeri a 64 bit è allettante. Idealmente, vuoi minimizzare il numero di creazioni di classe esplicite.

Utilizzando c_longlong, si potrebbe fare qualcosa di simile (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)) 

    ... 

In questo modo il risultato di ll(2 ** 63) - 1 sarà davvero 9223372036854775807. Questa costruzione potrebbe tuttavia comportare una penalizzazione delle prestazioni, quindi a seconda di cosa si vuole fare esattamente, la definizione di una classe come quella sopra potrebbe non valerne la pena. In caso di dubbi, utilizzare timeit.

3

La cosa più veloce è probabilmente quello di troncare il risultato a 64 bit da soli:

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

Ovviamente si può definire un tipo numerico che fa automaticamente questo ogni volta che si fa alcun tipo di operazione aritmetica:

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) 

    ... 

ma che non è particolarmente "veloce" da implementare.

1

Dai un'occhiata al modulo ctypes, è usato per chiamare DLL/librerie esterne da python. C'è un alcuni tipi di dati che corrispondono a tipi C, ad esempio

classe c_longlong

10

È possibile utilizzare numpy? Ha un tipo int64 che fa esattamente quello che vuoi.

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 

E 'trasparente agli utenti, a differenza l'esempio ctypes, ed è codificato in C, in modo che sarà più veloce rispetto a rotazione la propria classe in Python. Numpy può essere più grande delle altre soluzioni, ma se stai facendo analisi numerica, apprezzerai averlo.