Прокрадывание неподписанных значений из Jython, через Java, в C и обратно


Я участвую в проекте, где мы связываем API C в Jython (через Java). Мы столкнулись с проблемами с неподписанными значениями (поскольку Java их не поддерживает). Мы можем использовать кастинг между Java и C, но переход от Jython к Java-более сложная задача.

Я написал некоторые функции "кастинга" в Python. Они преобразуют битовый шаблон, представляющий знаковое или беззнаковое значение, в тот же битовый шаблон, представляющий противоположный знак.

Например:

>>> u2s(0xFFFFFFFF)
-1L

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

Есть ли еще элегантный способ обработки такого рода преобразований знаков между Jython и Java? Кто-нибудь пытался сделать это раньше?

Вот весь модуль:

__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()

Я пошел и проверить мой код против принято отвечать в языка Jython. Принятый ответ работает примерно на 1/3 лучше! Я только протестировал версию с явно определенной шириной.

Отредактируйте мой предоставленный код следующим образом, чтобы запустить тест для себя:

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
1 2

1 ответ:

Модульstruct естественно подходит для этого

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]

Для поддержки всех общих Ширин

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]

Для поддержки любой ширины до 64 бит

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)

Если вам нужно поддерживать ширину выше 64 бит

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)