web-dev-qa-db-ja.com

Python整数の逆ビット

10進整数(例:65)が与えられた場合、Pythonの基になるビットをどのように反転させるのですか?すなわち。次の操作:

65 → 01000001 → 10000010 → 130

このタスクは3つのステップに分けられるようです。

  1. 10進整数をバイナリ表現に変換します
  2. ビットを逆にする
  3. 10進数に戻す

ステップ2と3は非常に簡単に思えます( this および this SOステップ#2に関連する質問)を参照してください)ステップ1で:ステップ1の問題は、ゼロを埋めて完全な10進表現を取得することです(つまり、1000001ではなく65 = 01000001)。

私は周りを検索しましたが、何も見つからないようです。

25
David Chouinard
int('{:08b}'.format(n)[::-1], 2)

8の代わりに、任意の充填長さを指定できます。本当に空想を得たい場合は、

b = '{:0{width}b}'.format(n, width=width)
int(b[::-1], 2)

プログラムで幅を指定できます。

35
nneonneo
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)次のループで、新しいビットが追加されたとき。

5
Jay Wong

もっと高速にしたい場合は、 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
4
Bruce

「10進整数をバイナリ表現に変換する」必要はなく、方法もありません。すべてのPython整数はバイナリとして表されます;便宜上、それらを印刷するとき、それらは単に10進数に変換されます。

このソリューション を反転問題にしたい場合は、適切なnumbitsを見つけるだけです。これを手動で指定するか、 n.bit_length() で整数nを表すのに必要なビット数を計算できます(Python 2.7および3.1)。

ただし、65の場合、65がこれ以上ビットを必要とする理由はないため、7が得られます。 (最も近い8の倍数に切り上げたい場合があります...)

4
Fred Foo

シフトとマスクを使用して、数値の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))
3
Paul Hankin

最善の方法は、ビットごとにシフトすることです

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))
1
Sudip Ghimire

通常、この操作を数字の配列に適用する必要があり、単一の数字には適用する必要はありません。速度を上げるには、おそらく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
Sof

それを行うもう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))
0
bluefoggy