Законы булевой алгебры и упрощение схем

Урок показывает законы булевой алгебры, которыми инженеры упрощают схемы — меньше вентилей значит дешевле, быстрее и холоднее.

Упрощение булева выражения — преобразование формулы к эквивалентной, но с меньшим числом операций; в железе это прямо означает меньше транзисторов.

Зачем упрощать

Каждый вентиль — это транзисторы, площадь, задержка и потребление энергии. Если функцию можно вычислить пятью вентилями вместо двадцати, схема выйдет дешевле, быстрее и будет меньше греться. Поэтому булева алгебра — не абстракция, а инструмент оптимизации, которым пользуются ежедневно при проектировании процессоров.

Основные законы

ЗаконФормула
Идемпотентностьa AND a = a; a OR a = a
Поглощениеa OR (a AND b) = a
Дистрибутивностьa AND (b OR c) = (a AND b) OR (a AND c)
Де Моргана (1)NOT(a AND b) = NOT a OR NOT b
Де Моргана (2)NOT(a OR b) = NOT a AND NOT b
Двойное отрицаниеNOT(NOT a) = a

Законы де Моргана — самые полезные

Они позволяют «протолкнуть» отрицание внутрь скобок, меняя AND на OR. Это нужно постоянно: и при упрощении схем, и при переписывании условий в коде. «НЕ (идёт дождь И холодно)» равно «НЕ дождь ИЛИ НЕ холодно». Проверим все законы исчерпывающим перебором (это и есть способ доказать булево тождество):

def NOT(a): return 1 - a
def AND(a,b): return a & b
def OR(a,b):  return a | b

def prove(name, lhs, rhs, nvars=2):
    ok = True
    import itertools
    for vals in itertools.product((0,1), repeat=nvars):
        if lhs(*vals) != rhs(*vals):
            ok = False
    print(f"{'OK ' if ok else 'НЕТ'} {name}")

prove("Де Морган: NOT(a AND b) == NOT a OR NOT b",
      lambda a,b: NOT(AND(a,b)),
      lambda a,b: OR(NOT(a), NOT(b)))
prove("Поглощение: a OR (a AND b) == a",
      lambda a,b: OR(a, AND(a,b)),
      lambda a,b: a)
prove("Дистрибутивность: a AND (b OR c) == (a AND b) OR (a AND c)",
      lambda a,b,c: AND(a, OR(b,c)),
      lambda a,b,c: OR(AND(a,b), AND(a,c)), nvars=3)

Вывод:

OK  Де Морган: NOT(a AND b) == NOT a OR NOT b
OK  Поглощение: a OR (a AND b) == a
OK  Дистрибутивность: a AND (b OR c) == (a AND b) OR (a AND c)

Как работает под капотом: упрощаем реальное выражение

Пусть схема вычисляет F = (a AND b) OR (a AND NOT b). Вынесем a за скобку (дистрибутивность): F = a AND (b OR NOT b). Но b OR NOT b = 1 всегда. Значит F = a. Четыре вентиля схлопнулись в провод! Проверим:

def F_naive(a, b):
    return (a & b) | (a & (1 - b))

def F_simplified(a, b):
    return a

print("a b | naive | simplified")
for a in (0,1):
    for b in (0,1):
        print(f"{a} {b} |   {F_naive(a,b)}   |     {F_simplified(a,b)}")

Вывод:

a b | naive | simplified
0 0 |   0   |     0
0 1 |   0   |     0
1 0 |   1   |     1
1 1 |   1   |     1

Зачем это программисту: де Морган в коде каждый день

Законы булевой алгебры — это не только про железо; программист применяет их в каждом сложном условии, часто не называя по имени. Когда вы переписываете if not (a and b) в более читаемое if not a or not b — это закон де Моргана. Когда инвертируете условие цикла или раскрываете отрицание в фильтре базы данных, вы пользуетесь теми же правилами. Особенно коварна типичная ошибка: отрицание not (x > 0 and y > 0) новички часто «упрощают» в x <= 0 and y <= 0, тогда как де Морган требует or: x <= 0 or y <= 0. Знание закона спасает от целого класса логических багов, которые иначе ловятся только мучительной отладкой.

Та же алгебра объясняет приём «ранний выход»: длинную цепочку условий часто можно сократить, заметив, что один член поглощает другой (закон поглощения) или что часть всегда истинна. Читаемость и корректность кода тут идут рука об руку с экономией вентилей в схеме — это буквально одна и та же математика, применённая на разных этажах башни абстракций.

Глубже: карты Карно и почему ручное упрощение ненадёжно

Упрощать выражения «на глаз» — занятие коварное: легко остановиться на форме, которая кажется простой, но на деле не минимальна, или, хуже того, ошибиться в преобразовании. Поэтому инженеры пользуются систематическими методами. Для трёх-четырёх переменных это карта Карно — таблица, в которой соседние клетки отличаются ровно одним битом, благодаря чему «склеиваемые» члены оказываются рядом и видны глазом как прямоугольники единиц. Карта Карно гарантированно даёт минимальную форму там, где ручная алгебра может застрять. Для большего числа переменных применяют алгоритмический метод Квайна — Мак-Класки, который компьютер выполняет автоматически.

Важно понимать почему склеивание вообще возможно: оно опирается ровно на тождество из примера выше, b OR NOT b = 1. Если две строки таблицы истинности отличаются только значением одной переменной, а результат у них одинаков, эта переменная «безразлична» и выпадает — четыре вентиля схлопываются в провод. Карта Карно — это лишь удобный способ увидеть все такие склейки сразу.

Историческая справка и предел: минимизация — это дорого

Методы минимизации появились не из академического любопытства, а из суровой экономики ранней электроники: в 1950-х каждый логический элемент был дорогой и громоздкой деталью, и сократить схему на пару вентилей значило сэкономить реальные деньги и место. Карту предложил Морис Карно в 1953 году именно как инженерный инструмент. Любопытно, что задача поиска абсолютно минимальной схемы в общем случае вычислительно тяжела (NP-трудна) — для больших функций даже компьютер не находит идеал за разумное время и довольствуется «достаточно хорошим». Поэтому современные средства автоматизации проектирования (EDA), синтезирующие процессоры из описаний на языках вроде Verilog, применяют умные эвристики, прямые наследники де Моргана и карт Карно. Так законы из этого урока живут внутри инструментов, проектирующих чипы, которые вы держите в руках.

Частые ошибки

  • Неправильно применять де Моргана. Меняется не только связка (AND↔OR), но и инвертируется каждый член.
  • Упрощать «на глаз» без проверки. Таблица истинности (перебор) — надёжный способ доказать эквивалентность.
  • Игнорировать карты Карно. Для 3–4 переменных карта Карно даёт минимальную форму быстрее ручных преобразований.

Итог

  • Законы булевой алгебры позволяют сокращать число вентилей в схеме.
  • Законы де Моргана «проталкивают» отрицание, меняя AND на OR и наоборот.
  • Любое булево тождество доказывается перебором всех комбинаций входов.
Проверьте себя
1. Как по закону де Моргана раскрыть NOT(a OR b)?
ANOT a OR NOT b
BNOT a AND NOT b
Ca AND b
DNOT(a) OR b
2. Чему равно выражение a OR (a AND b)?
Aa AND b
Ba
Cb
D1
3. Зачем упрощать булевы выражения при проектировании схем?
AЧтобы код выглядел красивее
BМеньше вентилей — дешевле, быстрее и меньше энергопотребление
CЧтобы увеличить число транзисторов
DЭто требование стандарта