Python int.bit_count()徹底解説:2進数の1の数を高速カウントする方法
int.bit_count()とは
int.bit_count()は、Python 3.10で導入されたメソッドで、整数の2進表現における1のビット数(ハミング重み)を効率的にカウントします。
# 基本的な使用例
numbers = [5, 7, 15, 255]
for num in numbers:
binary = bin(num)
count = num.bit_count()
print(f"{num:3d}: {binary:>10s} → 1の数: {count}")
bit_count()の基本動作
正の整数での動作
# 様々な正の整数での例
test_numbers = [1, 2, 3, 4, 7, 8, 15, 16, 31, 255]
print("正の整数でのbit_count():")
print("数値 | 2進数 | 1の数")
print("------|-----------|------")
for num in test_numbers:
binary_str = bin(num)[2:] # '0b'プレフィックスを除去
count = num.bit_count()
print(f"{num:5d} | {binary_str:>9s} | {count:5d}")
ゼロでの動作
# ゼロの場合
zero = 0
print(f"0の2進数: {bin(zero)}")
print(f"0のbit_count(): {zero.bit_count()}")
大きな数での動作
# 大きな数での例
large_numbers = [1023, 1024, 2047, 2**20 - 1, 2**32 - 1]
print("大きな数でのbit_count():")
for num in large_numbers:
binary_len = len(bin(num)) - 2 # '0b'を除いた桁数
count = num.bit_count()
print(f"{num:>10d}: {binary_len:2d}桁, 1の数: {count:2d}")
負の数でのbit_count()
負の数の扱い
# 負の数でのbit_count()
negative_numbers = [-1, -2, -3, -4, -7, -8]
print("負の数でのbit_count():")
print("数値 | bit_count() | 説明")
print("-----|-------------|-----")
for num in negative_numbers:
try:
count = num.bit_count()
print(f"{num:4d} | {count:11d} | 無限に続く1のため")
except ValueError as e:
print(f"{num:4d} | エラー | {e}")
負の数の代替処理方法
def bit_count_negative_safe(n):
"""負の数に対応したbit_count"""
if n >= 0:
return n.bit_count()
else:
# 負の数の場合は絶対値のbit_countを返す
return abs(n).bit_count()
def bit_count_twos_complement(n, bit_width=32):
"""2の補数表現でのbit_count"""
if n >= 0:
return n.bit_count()
else:
# 指定ビット幅での2の補数表現
mask = (1 << bit_width) - 1
twos_complement = (~abs(n) + 1) & mask
return bin(twos_complement).count('1')
# テスト
test_vals = [5, -5, 7, -7]
for val in test_vals:
safe_count = bit_count_negative_safe(val)
twos_count = bit_count_twos_complement(val, 8)
print(f"{val:3d}: safe={safe_count}, 2's complement(8bit)={twos_count}")
bit_count()の実装パフォーマンス
他の実装方法との比較
def bit_count_manual(n):
"""手動でのbit_count実装"""
if n < 0:
raise ValueError("負の数は未対応")
count = 0
while n:
count += n & 1
n >>= 1
return count
def bit_count_bin_string(n):
"""文字列変換による実装"""
if n < 0:
raise ValueError("負の数は未対応")
return bin(n).count('1')
def bit_count_brian_kernighan(n):
"""Brian Kernighanのアルゴリズム"""
if n < 0:
raise ValueError("負の数は未対応")
count = 0
while n:
n &= n - 1 # 最下位の1ビットを除去
count += 1
return count
# 正確性の検証
test_num = 12345
methods = [
("built-in bit_count", lambda x: x.bit_count()),
("manual", bit_count_manual),
("bin string", bit_count_bin_string),
("Brian Kernighan", bit_count_brian_kernighan)
]
print(f"数値 {test_num} ({bin(test_num)}) の結果比較:")
for name, func in methods:
result = func(test_num)
print(f"{name:20s}: {result}")
パフォーマンス測定
import time
def benchmark_bit_count_methods():
"""bit_count実装方法の性能比較"""
test_numbers = list(range(1, 10001))
iterations = 100
methods = [
("int.bit_count()", lambda nums: [n.bit_count() for n in nums]),
("bin().count('1')", lambda nums: [bin(n).count('1') for n in nums]),
("manual loop", lambda nums: [bit_count_manual(n) for n in nums])
]
print("パフォーマンス比較結果:")
for name, method in methods:
start = time.time()
for _ in range(iterations):
results = method(test_numbers)
elapsed = time.time() - start
print(f"{name:20s}: {elapsed:.6f}秒")
benchmark_bit_count_methods()
実用的な応用例
ハミング距離の計算
def hamming_distance(a, b):
"""2つの整数間のハミング距離"""
return (a ^ b).bit_count()
# ハミング距離の例
pairs = [(5, 3), (15, 7), (255, 127), (1024, 512)]
print("ハミング距離の計算:")
for a, b in pairs:
distance = hamming_distance(a, b)
xor_result = a ^ b
print(f"{a:4d} XOR {b:4d} = {xor_result:4d} ({bin(xor_result):>10s}) → 距離: {distance}")
人口カウント(Population Count)
def analyze_bit_patterns(numbers):
"""ビットパターンの分析"""
results = []
for num in numbers:
bit_count = num.bit_count()
bit_length = num.bit_length() if num > 0 else 1
density = bit_count / bit_length if bit_length > 0 else 0
results.append({
'number': num,
'binary': bin(num),
'bit_count': bit_count,
'bit_length': bit_length,
'density': density
})
return results
# ビットパターン分析の実行
test_nums = [7, 15, 31, 63, 85, 170, 255]
analysis = analyze_bit_patterns(test_nums)
print("ビットパターン分析:")
print("数値 | 2進数 | 1の数 | 桁数 | 密度")
print("------|------------|-------|------|------")
for result in analysis:
print(f"{result['number']:5d} | {result['binary']:>10s} | {result['bit_count']:5d} | {result['bit_length']:4d} | {result['density']:.3f}")
チェックサムとしての活用
def simple_checksum(data):
"""ビットカウントを使った簡単なチェックサム"""
checksum = 0
for byte_val in data:
checksum += byte_val.bit_count()
return checksum % 256
def verify_data_integrity(original_data, received_data):
"""データ整合性の簡易チェック"""
original_checksum = simple_checksum(original_data)
received_checksum = simple_checksum(received_data)
return original_checksum == received_checksum, original_checksum, received_checksum
# データ整合性テスト
original = [0xFF, 0xAA, 0x55, 0x00, 0x0F]
received_ok = [0xFF, 0xAA, 0x55, 0x00, 0x0F] # 正常
received_ng = [0xFF, 0xAA, 0x54, 0x00, 0x0F] # 1ビット変化
print("データ整合性チェック:")
is_ok, orig_sum, recv_sum = verify_data_integrity(original, received_ok)
print(f"正常データ: 整合性={is_ok}, チェックサム={orig_sum}=={recv_sum}")
is_ok, orig_sum, recv_sum = verify_data_integrity(original, received_ng)
print(f"破損データ: 整合性={is_ok}, チェックサム={orig_sum}!={recv_sum}")
ビット操作での組み合わせ
ビットマスクとの組み合わせ
def analyze_permissions(permission_bits):
"""権限ビットの解析"""
# 権限の定義
READ = 0b100 # 4
WRITE = 0b010 # 2
EXECUTE = 0b001 # 1
permissions = []
if permission_bits & READ:
permissions.append('READ')
if permission_bits & WRITE:
permissions.append('WRITE')
if permission_bits & EXECUTE:
permissions.append('EXECUTE')
active_bits = permission_bits.bit_count()
return {
'permissions': permissions,
'binary': bin(permission_bits),
'active_count': active_bits,
'total_possible': 3
}
# 権限パターンの分析
permission_patterns = [0b000, 0b001, 0b010, 0b100, 0b111, 0b101]
print("権限ビット分析:")
for pattern in permission_patterns:
analysis = analyze_permissions(pattern)
perms = ', '.join(analysis['permissions']) if analysis['permissions'] else 'None'
print(f"{analysis['binary']:>5s}: {perms:20s} (アクティブ: {analysis['active_count']}/3)")
サブセット生成での活用
def generate_subsets_by_bit_count(items, target_count):
"""指定されたビット数のサブセットを生成"""
n = len(items)
subsets = []
# 0から2^n-1まで全ての組み合わせを確認
for i in range(2**n):
if i.bit_count() == target_count:
subset = [items[j] for j in range(n) if i & (1 << j)]
subsets.append(subset)
return subsets
# サブセット生成の例
fruits = ['apple', 'banana', 'cherry', 'date']
print(f"フルーツリスト: {fruits}")
for count in range(len(fruits) + 1):
subsets = generate_subsets_by_bit_count(fruits, count)
print(f"\n{count}個選ぶ組み合わせ ({len(subsets)}通り):")
for subset in subsets:
print(f" {subset}")
バイナリファイル解析での活用
ファイルの0/1ビット分布解析
def analyze_file_bit_distribution(file_path):
"""ファイルのビット分布を解析"""
try:
with open(file_path, 'rb') as f:
data = f.read()
total_bits = len(data) * 8
one_bits = sum(byte.bit_count() for byte in data)
zero_bits = total_bits - one_bits
return {
'file_size_bytes': len(data),
'total_bits': total_bits,
'one_bits': one_bits,
'zero_bits': zero_bits,
'one_ratio': one_bits / total_bits if total_bits > 0 else 0,
'entropy_estimate': min(one_bits, zero_bits) / total_bits * 2 if total_bits > 0 else 0
}
except FileNotFoundError:
return None
# サンプルデータでのテスト
import tempfile
import os
# テスト用ファイルを作成
test_data = bytes([0xFF, 0x00, 0xAA, 0x55, 0x0F, 0xF0])
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
temp_file.write(test_data)
temp_path = temp_file.name
# ファイル解析
analysis = analyze_file_bit_distribution(temp_path)
if analysis:
print("ファイルビット分布解析:")
print(f" ファイルサイズ: {analysis['file_size_bytes']} bytes")
print(f" 総ビット数: {analysis['total_bits']}")
print(f" 1ビット数: {analysis['one_bits']}")
print(f" 0ビット数: {analysis['zero_bits']}")
print(f" 1の割合: {analysis['one_ratio']:.3f}")
print(f" エントロピー推定: {analysis['entropy_estimate']:.3f}")
# テンポラリファイルを削除
os.unlink(temp_path)
まとめ
int.bit_count()は、Python 3.10で導入された効率的な1ビットカウント機能で、従来の文字列変換や手動ループよりも高速に動作します。ハミング距離計算、チェックサム生成、権限管理、データ解析など、様々な場面でビット操作と組み合わせて活用できます。負の数では無限に続く1が存在するため使用できませんが、適切な前処理により対応可能です。効率的なビット演算処理において、bit_count()は重要なツールとなります。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座


