0 и 1 в бинарных системах: почему компьютер работает на двух состояниях

0 и 1 в бинарных системах: почему компьютер работает на двух состояниях Полезное

0 и 1 в бинарной (двоичной) системе — это две цифры, которыми записывается любое число, а в компьютере — условные имена двух различимых состояний электронной схемы. Сами по себе «нолик» и «единичка» внутри процессора не лежат: там есть напряжение, заряд или намагниченность, которые схема относит к одному из двух классов.

В статье разберем, почему состояний именно два, как транзистор их переключает и как из элементов И, ИЛИ, НЕ получается сложение чисел. Код проверен на Python 3.14 30 сентября 2026 года.

Что означают 0 и 1: число, логика и физика

За парой «0 и 1» стоят четыре разных понятия, и их часто называют одним словом. Разведем их сразу.

Термин Что это Пример
Двоичная цифра знак в записи числа по основанию 2 в числе 101 три цифры
Бит единица информации: выбор одного из двух вариантов ответ «да» или «нет»
Логическое значение «ложь» или «истина» в булевой алгебре результат сравнения 3 > 2
Логический уровень диапазон напряжений, который схема считает нулем или единицей от 2,0 В и выше — единица

Сквозная цепочка на одном примере: число 5 -> двоичная запись 101 -> три бита -> три проводника с уровнями «высокий, низкий, высокий». Математика отвечает за первую стрелку, электроника — за последнюю.

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

Как переводить числа между системами счисления, разобрано в статье про двоичную систему счисления. Здесь нас интересует другое: почему железу удобны именно два состояния.

Почему состояний два: запас по помехам

Напряжение в реальной схеме никогда не равно ровно 0 или ровно 5 вольт. На него влияют соседние проводники, нагрев, разброс параметров деталей, просадки питания. Поэтому логический уровень — это не точка, а диапазон.

Классический пример — микросхемы ТТЛ с питанием 5 В. Выход обязан выдать ноль не выше 0,4 В и единицу не ниже 2,4 В. Вход соглашается считать нулем все до 0,8 В, а единицей — все от 2,0 В. Разница в 0,4 В с каждой стороны — запас по помехам: наводка такой величины не изменит прочитанное значение.

Между 0,8 и 2,0 В лежит запрещенная зона. В ней результат не определен, и схему проектируют так, чтобы сигнал проскакивал эту зону быстро и не задерживался в ней.

Теперь представим, что мы хотим хранить в одном проводнике не бит, а десятичную цифру. В те же 5 В придется уместить десять уровней, и расстояние между соседними сократится в девять раз. Посчитаем, что это дает, на простой модели.

import random

SUPPLY = 5.0      # напряжение питания, В
SIGMA = 0.3       # разброс помехи, В (учебное значение)
TRIALS = 100_000


def error_rate(levels: int, rng: random.Random) -> float:
    """Доля неверно прочитанных цифр при заданном числе уровней."""
    step = SUPPLY / (levels - 1)
    errors = 0
    for _ in range(TRIALS):
        digit = rng.randrange(levels)
        voltage = digit * step + rng.gauss(0, SIGMA)
        read = min(levels - 1, max(0, round(voltage / step)))
        errors += read != digit
    return errors / TRIALS


rng = random.Random(1)
for levels in (2, 3, 10):
    step = SUPPLY / (levels - 1)
    rate = error_rate(levels, rng)
    print(f"уровней: {levels:2}  шаг: {step:.2f} В  ошибок: {rate:.2%}")

Программа сто тысяч раз «передает» случайную цифру, добавляет к напряжению случайную помеху и читает ближайший уровень. Вывод:

уровней:  2  шаг: 5.00 В  ошибок: 0.00%
уровней:  3  шаг: 2.50 В  ошибок: 0.00%
уровней: 10  шаг: 0.56 В  ошибок: 32.05%

При одной и той же помехе два уровня читаются без ошибок, три — почти без ошибок (в этом прогоне 2 неверных чтения из 100 000, при выводе они округлились до 0.00%), а десять — с ошибкой почти в каждом третьем случае. Это упрощенная модель: помеха взята нормальной с разбросом 0,3 В, в реальных схемах она меньше и устроена иначе. Но зависимость верная: чем больше уровней в том же диапазоне, тем точнее и дороже должны быть детали.

Транзистор как ключ

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

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

В распространенной технологии КМОП транзисторы ставят парами: один соединяет выход с питанием, другой — с землей. Простейшая схема из такой пары — инвертор, элемент НЕ. Низкий уровень на входе открывает «верхний» транзистор, и выход подтягивается к питанию. Высокий уровень открывает «нижний», и выход уходит к земле.

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

Логические элементы И, ИЛИ, НЕ

Из ключей собирают логические элементы — схемы, выход которых зависит от входов по правилам булевой алгебры. Базовых операций три.

Элемент Правило Когда на выходе 1
НЕ инверсия на входе 0
И логическое умножение на обоих входах 1
ИЛИ логическое сложение хотя бы на одном входе 1

На практике в КМОП проще всего делается элемент И-НЕ: для двух входов хватает четырех транзисторов. Остальные операции выражаются через него. Проверим это кодом: опишем только И-НЕ, а НЕ, И, ИЛИ и сложение чисел построим из него.

def nand(a: int, b: int) -> int:
    """Базовый элемент И-НЕ: 0 только когда оба входа равны 1."""
    for bit in (a, b):
        if type(bit) is not int or bit not in (0, 1):
            raise ValueError(f"ожидался бит 0 или 1, получено {bit!r}")
    return 0 if (a == 1 and b == 1) else 1


def not_(a):
    return nand(a, a)


def and_(a, b):
    return not_(nand(a, b))


def or_(a, b):
    return nand(not_(a), not_(b))


def xor(a, b):
    return and_(or_(a, b), nand(a, b))


def full_adder(a, b, carry_in):
    """Складывает три бита, возвращает (бит суммы, перенос)."""
    partial = xor(a, b)
    total = xor(partial, carry_in)
    carry_out = or_(and_(a, b), and_(partial, carry_in))
    return total, carry_out


def add4(x: str, y: str) -> str:
    """Складывает два 4-битных числа, записанных строками из 0 и 1."""
    for number in (x, y):
        if not isinstance(number, str) or len(number) != 4 or set(number) - {"0", "1"}:
            raise ValueError("нужна строка ровно из 4 символов 0 или 1")
    carry = 0
    result = []
    for a, b in zip(reversed(x), reversed(y)):   # от младшего бита к старшему
        total, carry = full_adder(int(a), int(b), carry)
        result.append(str(total))
    return str(carry) + "".join(reversed(result))


print("a b | НЕ a | a И b | a ИЛИ b")
for a in (0, 1):
    for b in (0, 1):
        print(f"{a} {b} |   {not_(a)}  |   {and_(a, b)}   |    {or_(a, b)}")

print("0110 + 0111 =", add4("0110", "0111"))
print("1111 + 0001 =", add4("1111", "0001"))

try:
    nand(2, 1)
except ValueError as error:
    print("ошибка:", error)

Программа печатает таблицу истинности, два результата сложения и сообщение об отказе на недопустимом входе:

a b | НЕ a | a И b | a ИЛИ b
0 0 |   1  |   0   |    0
0 1 |   1  |   0   |    1
1 0 |   0  |   0   |    1
1 1 |   0  |   1   |    1
0110 + 0111 = 01101
1111 + 0001 = 10000
ошибка: ожидался бит 0 или 1, получено 2

Первая сумма — это 6 + 7 = 13, вторая — 15 + 1 = 16. Пятый бит слева — перенос из старшего разряда: в четыре бита число 16 уже не помещается.

Функция add4 заранее проверяет, что в строках только символы 0 и 1. Без этой проверки int() принял бы и цифры других письменностей: арабско-индийская «١» читается как 1, и сумматор молча сложил бы такую строку.

Что здесь важно. Функция full_adder — полный сумматор на один разряд: исключающее ИЛИ дает бит суммы, а И с ИЛИ — перенос. Четыре таких сумматора подряд складывают четырехбитные числа, и в коде нет ни одного оператора + над числами — только комбинации И-НЕ.

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

Где 0 и 1 живут физически

Напряжение на проводнике — не единственный способ представить бит. Носитель зависит от устройства.

Устройство Чем отличаются 0 и 1 (упрощенно)
Логика процессора низкий или высокий уровень напряжения
Оперативная память DRAM конденсатор ячейки разряжен или заряжен
Флеш-память, SSD количество заряда в ячейке
Жесткий диск направление намагниченности участков пластины
Оптоволокно параметры светового сигнала

Общее у всех вариантов одно: состояние измеряют и сравнивают с порогом. Поэтому формула «единица — ток есть, ноль — тока нет» годится как первая интуиция, но не как описание устройства памяти.

Всегда ли состояний два

Нет, и это полезно знать, чтобы не считать двоичность законом природы.

  • ENIAC, построенный в США в 1945 году, хранил числа в десятичном виде на кольцевых счетчиках из электронных ламп.
  • «Сетунь», созданная в МГУ в 1958 году под руководством Николая Брусенцова, работала в троичной системе.
  • Современные флеш-накопители хранят в одной ячейке несколько бит: ячейка TLC различает восемь уровней заряда, то есть три бита. Платят за это сложным чтением и кодами исправления ошибок.

Вычислительная логика при этом осталась двоичной: для двух состояний элементы получаются самыми простыми, дешевыми и устойчивыми, а математический аппарат — булева алгебра — давно готов.

Идеи складывались долго. Лейбниц описал двоичную арифметику в работе 1703 года, Джордж Буль в 1847 году опубликовал алгебру логики, а Клод Шеннон в магистерской работе 1937 года показал, что релейные схемы описываются булевой алгеброй. Слово «бит» появилось в печати позже — в статье Шеннона 1948 года, где он приписал термин Джону Тьюки.

Выводы

  • 0 и 1 — это имена двух диапазонов физической величины, а не сами напряжения: между диапазонами оставлен запас по помехам.
  • Два состояния дают наибольшее расстояние между уровнями, поэтому схема из недорогих и неидеальных деталей читает их надежно.
  • Транзистор в ключевом режиме — дешевый элемент с двумя рабочими положениями (открыт и закрыт), а логический элемент восстанавливает сигнал до полного уровня.
  • Из И, ИЛИ, НЕ (и даже из одного И-НЕ) собирается сумматор, а значит и арифметика.
  • Двоичность — инженерный выбор: десятичные и троичные машины существовали, а флеш-память хранит несколько бит в ячейке.

Где применяется / связь с практикой

Понимание логических уровней нужно не только разработчикам процессоров. С ним сталкивается каждый, кто подключает датчик к микроконтроллеру, согласует устройства с питанием 3,3 и 5 В, читает документацию на микросхему или ищет, почему сигнал на длинном проводе читается неверно.

Освойте тему на практике

Системно эти темы — от закона Ома до транзисторных ключей и цифровых схем — разбираются на курсе «Электроника и электротехника». Познакомиться с форматом занятий можно на открытых уроках Otus.

FAQ

Чем бит отличается от байта?
Бит — один выбор из двух вариантов, байт — группа из восьми бит. Один байт принимает 256 разных значений.

Что будет, если напряжение попадет между нулем и единицей?
Результат не определен: разные входы могут прочитать такой сигнал по-разному, а элемент памяти может дольше обычного выбирать состояние. Поэтому сигналы в схеме меняют быстро, а читают по тактовому сигналу, когда они уже установились.

Квантовый компьютер тоже работает на 0 и 1?
Кубит до измерения описывается сочетанием двух состояний, но при измерении дает 0 или 1. Обычные компьютеры он не заменяет: это отдельный класс устройств для узкого круга задач.

OTUS Журнал
Скидка 5% 12-19 октября на курсы (popup)
Бесплатные открытые уроки (поп-ап)