← Назад к курсу
Битовые операции в Python
Урок: Битовые операции в Python
📚 Теория: Двоичная система и битовые операции
1. Двоичная система счисления
- Каждое число представляется последовательностью битов (0 и 1)
- Пример: 5 в двоичной = 101 (4 + 0 + 1 = 5)
- В Python можно посмотреть двоичное представление:
bin(5) # '0b101' format(5, '08b') # '00000101' (8 бит)
2. Основные битовые операции
2.1. AND (&) - Побитовое И
1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0
Пример: 5 & 3 = 101 & 011 = 001 = 1
2.2. OR (|) - Побитовое ИЛИ
1 | 1 = 1 1 | 0 = 1 0 | 1 = 1 0 | 0 = 0
Пример: 5 | 3 = 101 | 011 = 111 = 7
2.3. XOR (^) - Исключающее ИЛИ
1 ^ 1 = 0 1 ^ 0 = 1 0 ^ 1 = 1 0 ^ 0 = 0
Пример: 5 ^ 3 = 101 ^ 011 = 110 = 6
2.4. NOT (~) - Побитовое НЕ
Инвертирует все биты (в Python использует дополнительный код)
2.5. Сдвиги (<<, >>)
- x << n: сдвиг влево на n битов (умножение на 2ⁿ)
- x >> n: сдвиг вправо на n битов (целочисленное деление на 2ⁿ)
🔥 Лайфхаки и полезные трюки
1. Проверка чётности
def is_even(n):
return (n & 1) == 0
# Пример:
is_even(4) # True (100 & 001 = 000)
is_even(5) # False (101 & 001 = 001)
2. Проверка степени двойки
def is_power_of_two(n):
return n > 0 and (n & (n - 1)) == 0
# Пример:
is_power_of_two(16) # True
is_power_of_two(15) # False
3. Умножение/деление на степень двойки
# Умножение на 2^n
def multiply_by_power_of_two(x, n):
return x << n
# Деление на 2^n (целочисленное)
def divide_by_power_of_two(x, n):
return x >> n
# Пример:
multiply_by_power_of_two(5, 3) # 5 * 8 = 40
divide_by_power_of_two(40, 3) # 40 // 8 = 5
4. Получение младшего установленного бита
def get_lsb(n):
return n & -n
# Пример:
get_lsb(12) # 12 = 1100, -12 = 0100 (в доп. коде) → 0100 = 4
5. Установка/сброс бита
# Установить i-й бит (нумерация с 0)
def set_bit(n, i):
return n | (1 << i)
# Сбросить i-й бит
def clear_bit(n, i):
return n & ~(1 << i)
# Проверить i-й бит
def check_bit(n, i):
return (n >> i) & 1
# Пример:
n = 5 # 101
set_bit(n, 1) # 111 = 7
clear_bit(n, 0) # 100 = 4
check_bit(n, 2) # 1 (бит установлен)
6. Подсчет установленных битов
def count_set_bits(n):
count = 0
while n:
n &= (n - 1) # сбрасываем младший установленный бит
count += 1
return count
# Встроенная функция:
bin(5).count('1') # 2
📝 Практические задачи
Задача 1: Одиночное число
Дан массив, где каждое число встречается дважды, кроме одного. Найдите это число.
def single_number(nums):
result = 0
for num in nums:
result ^= num
return result
# Пример: [4, 1, 2, 1, 2] → 4
Задача 2: Проверка степени двойки
Напишите функцию, проверяющую является ли число степенью двойки.
def is_power_of_two(n):
# Ваш код здесь
pass
Задача 3: Инвертирование битов
Инвертируйте все биты в числе (в заданном диапазоне бит).
def invert_bits(n, num_bits=32):
mask = (1 << num_bits) - 1
return n ^ mask
# Пример: invert_bits(5, 4) → 1010 = 10
Задача 4: Найти два уникальных числа
Дан массив, где все числа встречаются дважды, кроме двух чисел. Найдите их.
def find_two_unique(nums):
xor_all = 0
for num in nums:
xor_all ^= num
# Находим младший установленный бит
lsb = xor_all & -xor_all
# Разделяем числа на две группы
num1, num2 = 0, 0
for num in nums:
if num & lsb:
num1 ^= num
else:
num2 ^= num
return num1, num2
Задача 5: Сумма без сложения
Реализуйте сложение двух чисел используя только битовые операции.
def add_without_plus(a, b):
while b != 0:
carry = a & b
a = a ^ b
b = carry << 1
return a
💡 Полезные паттерны
1. Создание маски
# Маска из n единиц mask = (1 << n) - 1 # Маска для битов i..j mask = ((1 << (j - i + 1)) - 1) << i
2. Извлечение диапазона битов
def extract_bits(n, i, j):
mask = ((1 << (j - i + 1)) - 1) << i
return (n & mask) >> i
3. Установка диапазона битов
def set_bits_range(n, i, j, value):
mask = ((1 << (j - i + 1)) - 1) << i
# Очищаем диапазон
n &= ~mask
# Устанавливаем новые значения
n |= (value << i) & mask
return n
🚀 Оптимизации с битовыми операциями
1. Быстрое вычисление 2ⁿ
# Вместо 2**n используйте: 1 << n # Быстрее и точнее для целых чисел
2. Проверка наличия общего бита
# Проверить, есть ли общие установленные биты
if (a & b) != 0:
print("Есть общие биты")
3. Быстрое переключение между 0 и 1
toggle = 0 toggle ^= 1 # Стало 1 toggle ^= 1 # Стало 0
📊 Таблица приоритетов операций
- ~ (побитовое НЕ)
- <<, >> (сдвиги)
- & (И)
- ^ (исключающее ИЛИ)
- | (ИЛИ)
🔍 Отладка и визуализация
def print_binary(n, bits=8):
print(f"{n:3} = {format(n & ((1 << bits) - 1), f'0{bits}b')}")
# Пример использования:
print_binary(5) # 5 = 00000101
print_binary(~5) # -6 = 11111010 (в доп. коде)
🎯 Упражнения для закрепления
- Реализуйте функцию для обмена значений двух переменных без временной переменной
- Напишите функцию, возвращающую следующую степень двойки для заданного числа
- Реализуйте проверку, является ли число палиндромом в двоичном представлении
- Напишите функцию для циклического сдвига битов влево и вправо
- Реализуйте умножение двух чисел используя только битовые операции
📌 Итог
Битовые операции — мощный инструмент для:
- Оптимизации вычислений
- Экономии памяти (хранение флагов в одном числе)
- Решения алгоритмических задач
- Низкоуровневого программирования
Помните: читаемость кода важнее микрооптимизаций. Используйте битовые операции там, где они действительно нужны и оправданы!