web-dev-qa-db-ja.com

Pythonの2の補数

pythonに組み込み関数があります。これは、 '111111111111'などのバイナリ文字列を 2の補数整数 -1に変換しますか?

56
Jim

最上位ビットが1の場合、2の補数は(1<<bits)を減算します。たとえば、8ビットを取ると、127から-128の範囲になります。

整数の2の補数の関数...

def twos_comp(val, bits):
    """compute the 2's complement of int value val"""
    if (val & (1 << (bits - 1))) != 0: # if sign bit is set e.g., 8bit: 128-255
        val = val - (1 << bits)        # compute negative value
    return val                         # return positive value as is

バイナリ文字列から行くのは特に簡単です...

binary_string = '1111' # or whatever... no '0b' prefix
out = twos_comp(int(binary_string,2), len(binary_string))

私にとってもう少し便利なのは、16進値(この例では32ビット)から行くことです...

hex_string = '0xFFFFFFFF' # or whatever... '0x' prefix doesn't matter
out = twos_comp(int(hex_string,16), 32)
64
travc

組み込みではありませんが、異常な長さの数値が必要な場合は、 bitstring モジュールを使用できます。

>>> from bitstring import Bits
>>> a = Bits(bin='111111111111')
>>> a.int
-1

同じオブジェクトは、次のようないくつかの方法で同等に作成できます。

>>> b = Bits(int=-1, length=12)

任意の長さのビットのストリングのように動作し、プロパティを使用して異なる解釈を取得します。

>>> print a.int, a.uint, a.bin, a.hex, a.oct
-1 4095 111111111111 fff 7777
20
Scott Griffiths

Python 3.2、バイト操作用の組み込み関数があります: https://docs.python.org/3.4/library/stdtypes.html#int.to_bytes =。

To_bytesとfrom_bytesを組み合わせることにより、

def twos(val_str, bytes):
    import sys
    val = int(val_str, 2)
    b = val.to_bytes(bytes, byteorder=sys.byteorder, signed=False)                                                          
    return int.from_bytes(b, byteorder=sys.byteorder, signed=True)

チェック:

twos('11111111', 1)  # gives -1
twos('01111111', 1)  # gives 127

Pythonの古いバージョンでは、travcの答えは良いですが、文字列ではなく整数を使用したい場合、負の値に対しては機能しません。 f(f(val)) == valが各valに対して真である2の補数関数は次のとおりです。

def twos_complement(val, nbits):
    """Compute the 2's complement of int value val"""
    if val < 0:
        val = (1 << nbits) + val
    else:
        if (val & (1 << (nbits - 1))) != 0:
            # If sign bit is set.
            # compute negative value.
            val = val - (1 << nbits)
    return val
10
Gaël Ecorchard
>>> bits_in_Word=12
>>> int('111111111111',2)-(1<<bits_in_Word)
-1

これは次の理由で機能します。

2進数の2の補数は、2の大きな累乗から数値を引いた値として定義されます(具体的には、Nビットの2の補数の2 ^ Nから)。数値の2の補数は、ほとんどの算術演算で元の数値の負のように動作し、自然な方法で正の数値と共存できます。

8
John La Rooy

これにより、ビット単位のロジックを使用して2の補数が効率的に得られます。

def twos_complement(value, bitWidth):
    if value >= 2**bitWidth:
        # This catches when someone tries to give a value that is out of range
        raise ValueError("Value: {} out of range of {}-bit value.".format(value, bitWidth))
    else:
        return value - int((value << 1) & 2**bitWidth)

使い方:

まず、ユーザーが指定されたビット範囲の範囲内の値を渡したことを確認します(たとえば、誰かが0xFFFFを指定して8ビットを指定します)その問題の別の解決策は、 (2 ** bitWidth)-1

結果を得るために、値は1ビット左にシフトされます。これにより、値のMSB(符号ビット)が2**bitWidthと論理積される位置に移動します。符号ビットが「0」の場合、減数は0になり、結果はvalue - 0になります。符号ビットが「1」の場合、減数は2**bitWidthになり、結果はvalue - 2**bitWidthになります

例1:パラメーターがvalue = 0xFF(255d、b11111111)およびbitWidth = 8の場合

  1. 0xFF-int((0xFF << 1)&2 ** 8)
  2. 0xFF-int((0x1FE)&0x100)
  3. 0xFF-int(0x100)
  4. 255〜256
  5. -1

例2:パラメーターがvalue = 0x1F(31d、b11111)およびbitWidth = 6の場合

  1. 0x1F-int((0x1F << 1)&2 ** 6)
  2. 0x1F-int((0x3E)&0x40)
  3. 0x1F-int(0x00)
  4. 31-0
  5. 31

例3:値= 0x80、ビット幅= 7

ValueError: Value: 128 out of range of 7-bit value.

例4:値= 0x80、bitWitdh = 8

  1. 0x80-int((0x80 << 1)&2 ** 8)
  2. 0x80-int((0x100)&0x100)
  3. 0x80-int(0x100)
  4. 128〜256
  5. -128

次に、他の人が既に投稿したものを使用して、ビット文字列をint(bitstring、2)に渡し、twos_complementメソッドのvalueパラメーターに渡します。

3
Tom Myddeltyn

いくつかの実装(単なる例示であり、使用することを意図したものではありません):

def to_int(bin):
    x = int(bin, 2)
    if bin[0] == '1': # "sign bit", big-endian
       x -= 2**len(bin)
    return x

def to_int(bin): # from definition
    n = 0
    for i, b in enumerate(reversed(bin)):
        if b == '1':
           if i != (len(bin)-1):
              n += 2**i
           else: # MSB
              n -= 2**i 
    return n
3
jfs

いいえ、 2の補数 バイナリ文字列を10進数に変換する組み込み関数はありません。

これを行う単純なユーザー定義関数:

def two2dec(s):
  if s[0] == '1':
    return -1 * (int(''.join('1' if x == '0' else '0' for x in s), 2) + 1)
  else:
    return int(s, 2)

この関数はビット幅をパラメーターとして受け取らないことに注意してください。代わりに、正の入力値を1つ以上の先行ゼロビットで指定する必要があります。

例:

In [2]: two2dec('1111')
Out[2]: -1

In [3]: two2dec('111111111111')
Out[3]: -1

In [4]: two2dec('0101')
Out[4]: 5

In [5]: two2dec('10000000')
Out[5]: -128

In [6]: two2dec('11111110')
Out[6]: -2

In [7]: two2dec('01111111')
Out[7]: 127
2
maxschlepzig

Erikb85がパフォーマンスを向上させたので、ここに travcの答え に対して Scott Griffiths ' があります。

In [534]: a = [0b111111111111, 0b100000000000, 0b1, 0] * 1000
In [535]: %timeit [twos_comp(x, 12) for x in a]
100 loops, best of 3: 8.8 ms per loop
In [536]: %timeit [bitstring.Bits(uint=x, length=12).int for x in a]
10 loops, best of 3: 55.9 ms per loop

したがって、bitstringは、 他の質問 に見られるように、intよりもほぼ1桁遅いです。しかし一方で、単純さを打ち負かすことは困難です。私はuintをビット文字列に変換してからintに変換しています。これを理解するため、またはバグを導入する場所を見つけるために、一生懸命not働かなければなりません。そして、スコットグリフィスの答えが示すように、同じアプリにとって役立つかもしれないクラスには、はるかに柔軟性があります。しかし、第三に、travcの答えは実際に何が起こっているのかを明確にします。初心者でも、2行のコードを読むだけで、符号なしintから2の補数符号付きintへの変換を理解できます。

とにかく、ビットを直接操作することに関する他の質問とは異なり、これは固定長intの算術を行うことに関するもので、奇妙なサイズのものです。したがって、パフォーマンスが必要かどうかは推測していますが、これはおそらくこれらのすべてがたくさんあるため、おそらくベクトル化する必要があるからです。 numpyへのtravcの回答の適応:

def twos_comp_np(vals, bits):
    """compute the 2's compliment of array of int values vals"""
    vals[vals & (1<<(bits-1)) != 0] -= (1<<bits)
    return vals

今:

In [543]: a = np.array(a)
In [544]: %timeit twos_comp_np(a.copy(), 12)
10000 loops, best of 3: 63.5 µs per loop

おそらくカスタムCコードでそれを打ち負かすことができますが、おそらくそうする必要はありません。

1
abarnert

誰かが逆方向を必要とする場合:

def num_to_bin(num, wordsize):
    if num < 0:
        num = 2**wordsize+num
    base = bin(num)[2:]
    padding_size = wordsize - len(base)
    return '0' * padding_size + base

for i in range(7, -9, -1):
    print num_to_bin(i, 4)

これを出力する必要があります:0111 0110 0101 0100 0011 0010 0001 0000 1111 1110 1101 1100 1011 1010 1001 1000

16進文字列の各値を2の補数バージョンに変換するバージョンを次に示します。


In [5159]: twoscomplement('f0079debdd9abe0fdb8adca9dbc89a807b707f')                                                                                                 
Out[5159]: '10097325337652013586346735487680959091'


def twoscomplement(hm): 
   twoscomplement='' 
   for x in range(0,len(hm)): 
       value = int(hm[x],16) 
       if value % 2 == 1: 
         twoscomplement+=hex(value ^ 14)[2:] 
       else: 
         twoscomplement+=hex(((value-1)^15)&0xf)[2:] 
   return twoscomplement            
0

私はPython 3.4.0を使用しています

Python 3では、データ型の変換にいくつかの問題があります。

だから...ここでは、16進文字列でうまく機能する(私のような)ヒントを紹介します。

16進データを取り、それを補完します。

a = b'acad0109'

compl = int(a,16)-pow(2,32)

result=hex(compl)
print(result)
print(int(result,16))
print(bin(int(result,16)))

結果= -1397948151または-0x5352fef7または '-0b1010011010100101111111011110111'

0
SnowBG

残念ながら、符号なし整数を2の補数の符号付き値にキャストする組み込み関数はありませんが、ビットごとの演算を使用してそうする関数を定義できます。

def s12(value):
    return -(value & 0b100000000000) | (value & 0b011111111111)

最初のビットごとのAND演算は、負の数を符号拡張するために使用され(最上位ビットが設定されます)、2番目は残りの11ビットを取得するために使用されます。これは、Pythonの整数が任意の精度の2の補数値として扱われるため、機能します。

次に、これをint関数と組み合わせて、2進数の文字列を符号なし整数形式に変換し、12ビットの符号付き値として解釈できます。

>>> s12(int('111111111111', 2))
-1
>>> s12(int('011111111111', 2))
2047
>>> s12(int('100000000000', 2))
-2048

この関数の優れた特性の1つは、べき等であるため、すでに署名された値が変更されないことです。

>>> s12(-1)
-1
0
dcoles

これは3バイトで機能します。 ライブコードはこちら

def twos_compliment(byte_arr):
   a = byte_arr[0]; b = byte_arr[1]; c = byte_arr[2]
   out = ((a<<16)&0xff0000) | ((b<<8)&0xff00) | (c&0xff)
   neg = (a & (1<<7) != 0)  # first bit of a is the "signed bit." if it's a 1, then the value is negative
   if neg: out -= (1 << 24)
   print(hex(a), hex(b), hex(c), neg, out)
   return out


twos_compliment([0x00, 0x00, 0x01])
>>> 1

twos_compliment([0xff,0xff,0xff])
>>> -1

twos_compliment([0b00010010, 0b11010110, 0b10000111])
>>> 1234567

twos_compliment([0b11101101, 0b00101001, 0b01111001])
>>> -1234567

twos_compliment([0b01110100, 0b11001011, 0b10110001])
>>> 7654321

twos_compliment([0b10001011, 0b00110100, 0b01001111])
>>> -7654321
0
D.Deriso

OKuLaw圧縮アルゴリズムPCM wavファイルタイプでこの問題が発生しました。そして、私が見つけたのは、2の補数が何らかのバイナリ数の負の値を作ることです ここに見られるように そしてそして wikipedia と相談した後、私はそれが本当だと思いました。

男は_least significant bit_を見つけて、その後すべてをめくると説明しました。上記のこれらの解決策はすべて私を助けなかったと言わなければなりません。 _0x67ff_を試してみると、_-26623_の代わりにいくつかの結果が出ました。誰かが_least significant bit_がデータのリストをスキャンしていることを知っていたとしても、ソリューションは機能したかもしれませんが、PCMのデータはさまざまなので、私は知りませんでした。だからここに私の答えがあります:

_max_data = b'\xff\x67' #maximum value i've got from uLaw data chunk to test

def twos_compliment(short_byte): # 2 bytes 
    short_byte = signedShort(short_byte) # converting binary string to integer from struct.unpack i've just shortened it.
    valid_nibble = min([ x*4 for x in range(4) if (short_byte>>(x*4))&0xf ])
    bit_shift = valid_nibble + min( [ x for x in [1,2,4,8] if ( ( short_byte>>valid_nibble )&0xf )&x ] )
    return (~short_byte)^( 2**bit_shift-1 )

data  = 0x67ff
bit4 = '{0:04b}'.format
bit16 = lambda x: ' '.join( map( bit4, reversed([ x&0xf, (x>>4)&0xf, (x>>8)&0xf, (x>>12)&0xf ]) ) )

# print( bit16(0x67ff) , ' : ', bit16( twos_compliment(  b'\xff\x67' ) ) )
# print( bit16(0x67f0) , ' : ', bit16( twos_compliment(  b'\xf0\x67' ) ) )
# print( bit16(0x6700) , ' : ', bit16( twos_compliment(  b'\x00\x67' ) ) )
# print( bit16(0x6000) , ' : ', bit16( twos_compliment(  b'\x00\x60' ) ) )
print( data, twos_compliment(max_data) )
_

コードは判読できないので、アイデアを説明します。

_## example data, for testing... in general unknown
data = 0x67ff # 26623 or 0110 0111 1111 1111 
_

これは単なる16進数の値であり、確認するためにテストが必要でしたが、一般的にはintの範囲内の任意の値になります。したがって、65535値の束全体をループしないように、_short integer_でnibbles(4ビット)で分割することを決定できます。以前に _bitwise operators_ を使用したことがない場合は、このようにすることができます。

_nibble_mask = 0xf # 1111
valid_nibble = []

for x in range(4): #0,1,2,3 aka places of bit value
    # for individual bits you could go 1<<x as you will see later

    # x*4 is because we are shifting bit places , so 0xFA>>4 = 0xF
    #     so 0x67ff>>0*4 = 0x67ff
    #     so 0x67ff>>1*4 = 0x67f
    #     so 0x67ff>>2*4 = 0x67
    #     so 0x67ff>>3*4 = 0x6
    # and nibble mask just makes it confided to 1 nibble so 0xFA&0xF=0xA
    if (data>>(x*4))&nibble_mask: valid_nibble.append(x*4) # to avoid multiplying it with 4 later 
_

そこで、_least significant bit_を検索しているので、ここではmin(valid_nibble )で十分です。ここで、最初のアクティブな(ビットが設定された)ニブルがある場所を取得しました。ここで必要なのは、最初の設定ビットが目的のニブルのどこにあるかを見つけることです。

_bit_shift = min(valid_nibble)
for x in range(4): 
    # in my example above [1,2,4,8] i did this to spare python calculating 
    ver_data = data>>min(bit_shift ) # shifting from 0xFABA to lets say 0xFA
    ver_data &= nibble_mask # from 0xFA to 0xA 
    if ver_data&(1<<x): 
        bit_shift += (1<<x)
        break
_

_~_と_^_を見ると、これに慣れていない人を混乱させる可能性があるため、ここで何かを明確にする必要があります:

XOR :_^_:2つの数字が必要です

この操作はちょっと非論理的です。2ビットごとにスキャンし、両方が1または0の場合は0になり、それ以外の場合は1になります。

_ 0b10110
^0b11100
--------- 
 0b01010   
_

そして別の例:

_ 0b10110
^0b11111
---------
 0b01001
_

_1's complement_ :_~_-他の番号は必要ありません

この操作は、数値のすべてのビットを反転します。これは私たちが求めているものと非常に似ていますが、最下位ビットを残しません。

_0b10110  
~  
0b01001
_

そして、ここでわかるように、1の賛辞はnumber XOR full set bits。


互いに理解したので、すべてのバイトを最下位ビット1の補数に復元することで_two's complement_を取得します。

_data = ~data # one's complement of data 
_

これにより、残念ながら数字のすべてのビットが反転したため、必要な数字を元に戻す方法を見つける必要があります。保持する必要があるビットのビット位置であるため、_bit_shift_でそれを行うことができます。したがって、データの数を計算するときに、いくつかのビット数で保持できるのは_2**n_であり、ニブルの場合はビットの値で0を計算しているため16になります。

_2**4 = 16 # in binary 1 0000 
_

ただし、_1_の後にバイトが必要なので、それを使用して値を1減らして取得できます。

_2**4 -1 = 15 # in binary 0 1111 
_

具体的な例のロジックを見てみましょう:

_ 0b110110
 lsb = 2 # binary 10 

~0b110110
----------
 0b001001 # here is that 01 we don't like  

 0b001001
^0b000011 # 2**2 = 4 ; 4-1 = 3 in binary 0b11 
--------- 
 0b001010
_

これがあなたや、この同じ問題を抱え、解決策を見つけるために彼らのa **を調査した初心者に役立つことを願っています。私が書いたこのコードはfrankensteinコードであり、それを説明しなければならなかった理由を覚えておいてください。私のコードをきれいにしたい人がいれば、ゲストになってください。

0
Danilo