开发者

Sneaking unsigned values from Jython, through Java, to C and back again

开发者 https://www.devze.com 2023-01-23 14:07 出处:网络
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

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)
0

精彩评论

暂无评论...
验证码 换一张
取 消