2010-11-06 4 views
2

Je suis impliqué dans un projet où nous lions une API C en Jython (via Java). Nous avons rencontré des problèmes avec des valeurs non signées (puisque Java ne les supporte pas). Nous pouvons utiliser la conversion entre Java et C, mais passer de Jython à Java est une tâche plus difficile. J'ai écrit des fonctions de "casting" en Python. Ils convertissent un modèle binaire représentant une valeur signée ou non signée dans le même schéma de bits représentant le signe opposé.Importer des valeurs non signées de Jython, via Java, vers C et vice-versa

Par exemple:

>>> u2s(0xFFFFFFFF) 
-1L 

>>> hex(s2u(-1)) 
'0xffffffffL' 

Y at-il une façon plus élégante pour gérer ce type de conversions de signe entre Jython et Java? Est-ce que quelqu'un a déjà essayé de le faire?

est ici l'ensemble du module:

__all__ = ['u2s', 's2u'] 

def u2s(v,width=32): 
    """ 
    Convert a bit pattern representing an unsigned value to the 
    SAME BIT PATTERN representing a signed value. 

    >>> u2s(0xFFFFFFFF) 
    -1L 
    >>> u2s(0x7FFFFFFF) 
    2147483647L 
    """ 

    msb = int("1" + ((width - 1) * '0'), 2) 
    msk = int("1" * width, 2) 
    nv = v & msk 

    if 0 < (msb & nv): 
     return -1 * ((nv^msk) + 1) 
    else: 
     return nv 

def s2u(v,width=32): 
    """ 
    Convert a bit pattern representing a signed value to the 
    SAME BIT PATTERN representing an unsinged value. 

    >>> hex(s2u(-1)) 
    '0xffffffffL' 
    >>> hex(s2u(1)) 
    '0x1L' 
    """ 

    msk = int("1" * width, 2) 

    if 0 > v: 
     return msk & (((-1 * v)^msk) + 1) 
    else: 
     return msk & v 

if __name__ == "__main__": 
    import doctest 
    doctest.testmod() 

Je suis allé benchmarkée mon code VS la réponse acceptée dans Jython. La réponse acceptée est environ 1/3 meilleure! J'ai seulement testé la version avec des largeurs définies explicitement.

Modifier mon code fourni avec ce qui suit pour exécuter l'indice de référence pour vous-même:

def _u2s(v, width=32): 
    fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width] 
    return struct.unpack(fmt.lower(), struct.pack(fmt, v))[0] 

def _s2u(v, width=32): 
    fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width] 
    return struct.unpack(fmt, struct.pack(fmt.lower(), v))[0] 

if __name__ == "__main__": 
    import doctest 
    doctest.testmod() 

    import time 

    x = range(-1000000,1000000) 
    t1 = time.clock() 
    y = map(s2u, x) 
    t2 = time.clock() 

    print t2 - t1 

    _t1 = time.clock() 
    z = map(_s2u, x) 
    _t2 = time.clock() 

    print _t2 - _t1 

Répondre

4

Le module struct est un naturel pour cette

import struct 

def u2s(v): 
    return struct.unpack("i", struct.pack("I", v))[0] 

def s2u(v): 
    return struct.unpack("I", struct.pack("i", v))[0] 

Pour prendre en charge toutes les largeurs communes

import struct 

def u2s(v, width=32): 
    fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width] 
    return struct.unpack(fmt.lower(), struct.pack(fmt, v))[0] 

def s2u(v, width=32): 
    fmt = {8: "B", 16: "H", 32: "I", 64: "Q"}[width] 
    return struct.unpack(fmt, struct.pack(fmt.lower(), v))[0] 

Pour supporter n'importe quelle largeur jusqu'à 64 bits

import struct 

def u2s(v, width=32): 
    return struct.unpack("q",struct.pack("Q",v<<(64-width)))[0]>>(64-width) 

def s2u(v, width=32): 
    return struct.unpack("Q",struct.pack("q",v<<(64-width)))[0]>>(64-width) 

Si vous avez besoin pour soutenir la largeur au-dessus de 64 bits

def u2s(v, width=32): 
    return v if v < (1L<<(width-1)) else v - (1L<<width) 

def s2u(v, width=32): 
    return v if v >= 0 else v + (1L<<width) 
+0

J'espérais permettre de définir éventuellement la largeur. J'avais pris cela en compte. Je suppose que je pouvais seulement autoriser des largeurs prédéfinies. – John

+0

@John, la dernière partie de ma réponse fonctionne pour n'importe quelle largeur –

+0

@nibbler - Ah, merveilleux. Merci. – John

Questions connexes