2009-11-19 9 views
11

Je voudrais représenter une valeur en tant que 64bit signé long, de sorte que les valeurs supérieures à (2 ** 63) -1 sont représentées comme négatives, cependant Python long a une précision infinie. Y a-t-il un moyen "rapide" pour moi d'y parvenir?Python long type C 'long long'

Répondre

13

Vous pouvez utiliser 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 

C'est vraiment que une option si vous savoir avec certitude qu'un signed long long aura une largeur de 64 bits sur la machine cible.

Modifier:jorendorff's idea de définir une classe pour les nombres de 64 bits est attrayant. Idéalement, vous voulez minimiser le nombre de créations de classe explicites.

En utilisant c_longlong, vous pourriez faire quelque chose comme ça (Note: Python 3.x uniquement):

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 cette façon, le résultat de ll(2 ** 63) - 1 sera en effet 9223372036854775807. Cette construction peut entraîner une pénalité de performance, donc en fonction de ce que vous voulez faire exactement, définir une classe comme celle ci-dessus peut ne pas valoir le coup. En cas de doute, utilisez timeit.

3

Le plus rapide chose est probablement tronquer le résultat à 64 bits vous:

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

Vous pouvez bien sûr définir votre propre type numérique qui fait automatiquement chaque fois que vous faites une sorte d'opération arithmétique:

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) 

    ... 

mais cela n'est pas particulièrement "rapide" à implémenter.

1

Jetez un coup d'oeil au module ctypes, il est utilisé pour appeler des DLL/bibliothèques étrangères à partir de python. Il a certains types de données qui correspondent à des types C, par exemple

classe c_longlong

10

Pouvez-vous utiliser numpy? Il a un type int64 qui fait exactement ce que vous voulez.

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 

Il est transparent pour les utilisateurs, contrairement à l'exemple de ctypes, et il est codé en C de sorte qu'il sera plus rapide que rouler votre propre classe en Python. Numpy peut être plus grand que les autres solutions, mais si vous faites une analyse numérique, vous apprécierez de l'avoir.