10進整数(例:65)が与えられた場合、Pythonの基になるビットをどのように反転させるのですか?すなわち。次の操作:
65 → 01000001 → 10000010 → 130
このタスクは3つのステップに分けられるようです。
ステップ2と3は非常に簡単に思えます( this および this SOステップ#2に関連する質問)を参照してください)ステップ1で:ステップ1の問題は、ゼロを埋めて完全な10進表現を取得することです(つまり、1000001ではなく65 = 01000001)。
私は周りを検索しましたが、何も見つからないようです。
int('{:08b}'.format(n)[::-1], 2)
8の代わりに、任意の充填長さを指定できます。本当に空想を得たい場合は、
b = '{:0{width}b}'.format(n, width=width)
int(b[::-1], 2)
プログラムで幅を指定できます。
def reverse_bit(num):
result = 0
while num:
result = (result << 1) + (num & 1)
num >>= 1
return result
Pythonでは整数は実際にはバイナリであるため、整数を実際にバイナリに変換する必要はありません。
反転の考え方は、整数のインスペース反転を行うようなものです。
def reverse_int(x):
result = 0
pos_x = abs(x)
while pos_x:
result = result * 10 + pos_x % 10
pos_x /= 10
return result if x >= 0 else (-1) * result
ループごとに、元の数値は右端のビット(バイナリ)をドロップします。その右端のビットを取得し、2(<<1
)次のループで、新しいビットが追加されたとき。
もっと高速にしたい場合は、 http://leetcode.com/2011/08/reverse-bits.html で説明されている手法を使用できます。
def reverse_mask(x):
x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1)
x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2)
x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4)
x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8)
x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16)
return x
「10進整数をバイナリ表現に変換する」必要はなく、方法もありません。すべてのPython整数はバイナリとして表されます;便宜上、それらを印刷するとき、それらは単に10進数に変換されます。
このソリューション を反転問題にしたい場合は、適切なnumbits
を見つけるだけです。これを手動で指定するか、 n.bit_length()
で整数n
を表すのに必要なビット数を計算できます(Python 2.7および3.1)。
ただし、65の場合、65がこれ以上ビットを必要とする理由はないため、7が得られます。 (最も近い8の倍数に切り上げたい場合があります...)
シフトとマスクを使用して、数値のi番目のビットをテストできます。たとえば、65のビット6は(65 >> 6) & 1
。 1を右に数回シフトすることで、同様の方法でビットを設定できます。これらの洞察により、次のようなコードが得られます(「n」ビットのフィールドでxを反転します)。
def reverse(x, n):
result = 0
for i in xrange(n):
if (x >> i) & 1: result |= 1 << (n - 1 - i)
return result
print bin(reverse(65, 8))
最善の方法は、ビットごとにシフトすることです
def reverse_Bits(n, no_of_bits):
result = 0
for i in range(no_of_bits):
result <<= 1
result |= n & 1
n >>= 1
return result
# for example we reverse 12 i.e 1100 which is 4 bits long
print(reverse_Bits(12,4))
通常、この操作を数字の配列に適用する必要があり、単一の数字には適用する必要はありません。速度を上げるには、おそらくNumPy配列を使用する方が良いでしょう。 2つの解決策があります。
2番目のソリューションよりもx1.34高速:
import numpy as np
def reverse_bits_faster(x):
x = np.array(x)
bits_num = x.dtype.itemsize * 8
# because bitwise operations may change number of bits in numbers
one_array = np.array([1], x.dtype)
# switch bits in-place
for i in range(int(bits_num / 2)):
right_bit_mask = (one_array << i)[0]
left_bit = (x & right_bit_mask) << (bits_num - 1 - i * 2)
left_bit_mask = (one_array << (bits_num - 1 - i))[0]
right_bit = (x & left_bit_mask) >> (bits_num - 1 - i * 2)
moved_bits_mask = left_bit_mask | right_bit_mask
x = x & (~moved_bits_mask) | left_bit | right_bit
return x
遅いが、より理解しやすい( Sudip Ghimireによって提案されたソリューション に基づいて):
import numpy as np
def reverse_bits(x):
x = np.array(x)
bits_num = x.dtype.itemsize * 8
x_reversed = np.zeros_like(x)
for i in range(bits_num):
x_reversed = (x_reversed << 1) | x & 1
x >>= 1
return x_reversed
それを行うもう1つの方法は、両端からビットをループ処理し、相互に交換することです。これはEPI python book。
i = 0; j = 7
num = 230
print(bin(num))
while i<j:
# Get the bits from both end iteratively
if (x>>i)&1 != (x>>j)&1:
# if the bits don't match swap them by creating a bit mask
# and XOR it with the number
mask = (1<<i) | (1<<j)
num ^= mask
i += 1; j -= 1
print(bin(num))