Sneaking unsigned values from Jython, through Java, to C and back again
I'm involved in a project where we're binding a C API into Jython (through Java). We've run into issues with unsigned values (since Java doesn't support them). We can use casting between Java and C, but moving from Jython to Java is a harder task.
I wrote some 'casting' functions in Python. They convert a bit pattern representing a signed or unsigned value into the SAME BIT PATTERN representing the opposite sign.
For example:
>>> u2s(0xFFFFFFFF)
-1L
>>> hex(s2u(-1))
'0xffffffffL'
Is there a more elegant way to handle these sorts of sign conversions between Jython and Java? Has any one tried to do this before?
Here's the entire 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 sig开发者_开发百科ned 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()
I went and benchmarked my code VS the accepted answer in Jython. The accepted answer performs about 1/3 better! I only tested the version with explicitly defined widths.
Edit my supplied code with the following to run the benchmark for yourself:
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
The struct module is a natural fit for this
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]
To support all the common widths
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]
To support any width up to 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)
If you need to support widths above 64 bit
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)
精彩评论