2010-11-06 74 views
2

我參與了一個將C API綁定到Jython(通過Java)的項目。我們遇到了無符號值的問題(因爲Java不支持它們)。我們可以在Java和C之間使用Cast,但是從Jython轉換到Java是一件比較困難的任務。將無符號值從Jython偷渡到C,然後再返回

我在Python中寫了一些'casting'函數。它們將表示有符號或無符號值的位模式轉換爲表示相反符號的相同位模式。

例如:

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

我去了,我的基準測試VS代碼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 

回答

4

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

我希望以允許其選擇性地限定的寬度的寬度。我曾考慮過這一點。我想我只能允許預定義的寬度。 – John 2010-11-06 03:03:36

+0

@約翰,我的答案的最後部分適用於任何寬度 – 2010-11-06 03:35:04

+0

@nibbler - 啊,太棒了。謝謝。 – John 2010-11-06 12:55:18

相關問題