pythonに組み込み関数があります。これは、 '111111111111'などのバイナリ文字列を 2の補数整数 -1に変換しますか?
最上位ビットが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)
組み込みではありませんが、異常な長さの数値が必要な場合は、 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
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
>>> bits_in_Word=12
>>> int('111111111111',2)-(1<<bits_in_Word)
-1
これは次の理由で機能します。
2進数の2の補数は、2の大きな累乗から数値を引いた値として定義されます(具体的には、Nビットの2の補数の2 ^ Nから)。数値の2の補数は、ほとんどの算術演算で元の数値の負のように動作し、自然な方法で正の数値と共存できます。
これにより、ビット単位のロジックを使用して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の場合
例2:パラメーターがvalue = 0x1F(31d、b11111)およびbitWidth = 6の場合
例3:値= 0x80、ビット幅= 7
ValueError: Value: 128 out of range of 7-bit value.
例4:値= 0x80、bitWitdh = 8
次に、他の人が既に投稿したものを使用して、ビット文字列をint(bitstring、2)に渡し、twos_complementメソッドのvalueパラメーターに渡します。
いくつかの実装(単なる例示であり、使用することを意図したものではありません):
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
いいえ、 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
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コードでそれを打ち負かすことができますが、おそらくそうする必要はありません。
誰かが逆方向を必要とする場合:
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
私は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'
残念ながら、符号なし整数を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
これは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
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コードであり、それを説明しなければならなかった理由を覚えておいてください。私のコードをきれいにしたい人がいれば、ゲストになってください。