Прокрадывание неподписанных значений из 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 ответ:
Модуль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)