Представьте себе комнату с лампочкой и двумя выключателями. Ток идёт по проводам. У провода есть только два состояния: есть ток или нет тока. Это и есть двоичная система: 1 или 0. Комбинация выключателей задаёт, дойдёт ли ток до лампочки. Это и есть булева логика — правила, по которым выключатели соединены. AND (И): два выключателя последовательно, ток дойдёт, только если оба включены. OR (ИЛИ): два выключателя параллельно, ток дойдёт, если хотя бы один включён. NOT (НЕ): выключатель с перекидным контактом, нажал — ток не идёт, отпустил — идёт. XOR (исключающее ИЛИ): ток идёт, если выключатели в разных состояниях, один включён, другой выключен.
Обычный выключатель — это два контакта: один всегда на месте, другой либо касается его (ток идёт), либо нет (ток не идёт). Перекидной контакт, его ещё называют трёхпозиционным или SPDT, — это выключатель с тремя контактами: общий (нож), к нему всегда подходит ток; первый выход, ток уходит сюда, когда выключатель в одном положении; второй выход, ток уходит сюда, когда выключатель в другом положении. Представь стрелку на железной дороге. Поезд (ток) всегда идёт по общему пути, но на развилке стрелка направляет его либо на левый путь, либо на правый. Никогда — на оба сразу и никогда — никуда. Вот это и есть перекидной контакт: ток всегда куда-то идёт, но только в одну из двух сторон. Именно такие выключатели используют в коридорах, где свет можно включить у входа и выключить у выхода из коридора. Вы щёлкаете одним — свет загорается, щёлкаете другим — гаснет. Это и есть XOR.
Теперь самое главное: как из лампочек получить сложение? Представь, что у нас есть две лампочки — младший разряд и старший разряд. И два выключателя: A и B. Каждый выключатель — это одно из слагаемых (1 или 0). Мы хотим сложить A и B. Результат должен появиться на лампочках.
A B Что должно получиться Младшая лампочка Старшая лампочка
0 0 0 не горит не горит
0 1 1 горит не горит
1 0 1 горит не горит
1 1 2 (то есть «10») не горит горит
Обрати внимание на последнюю строку: когда оба выключателя включены (1 + 1), младшая лампочка не горит, а старшая горит. Это и есть число «10» в двоичной системе, то есть 2. Почему так? Потому что в двоичной системе нет цифры «2». Есть только 0 и 1. Когда мы складываем 1 и 1, получается «10»: ноль в младшем разряде и единица в старшем. Эта единица, которая «переезжает» в старший разряд, и называется перенос. Перенос — это когда в одном разряде получается слишком много, и «лишнее» переходит в следующий разряд. Представь, что у тебя есть только цифры от 0 до 9 (как в обычной жизни). Ты складываешь 7 + 5. Получается 12. Ты пишешь «2», а «1» переносишь в следующий разряд (десятки). Вот это и есть перенос. В двоичной системе то же самое, только цифр всего две: 0 и 1. Поэтому перенос возникает гораздо чаще. Например, 1 + 0 = 1 (переноса нет), 1 + 1 = 10 (перенос есть: единица уходит в старший разряд). Итог: перенос — это «единица, которая уходит в следующий разряд», когда в текущем разряде места больше нет.
А как вообще десятичные цифры, которыми мы пользуемся каждый день, превращаются в двоичные? Давай разберёмся популярно. В обычной жизни мы пользуемся десятью цифрами: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Это десятичная система. Когда мы пишем число 253, мы на самом деле имеем в виду 2 сотни, 5 десятков и 3 единицы. То есть 2 × 100 + 5 × 10 + 3 × 1. Каждый разряд — это степень десятки: единицы — 10⁰, десятки — 10¹, сотни — 10². В двоичной системе всё то же самое, только цифр не десять, а две: 0 и 1. И каждый разряд — это степень двойки, а не десятки. Самый правый разряд — это 2⁰ (то есть 1), следующий — 2¹ (то есть 2), следующий — 2² (то есть 4), потом 2³ (8), 2⁴ (16), 2⁵ (32), 2⁶ (64), 2⁷ (128), 2⁸ (256) и так далее. Чтобы перевести десятичное число в двоичное, нужно понять, из каких степеней двойки оно состоит. Есть простой способ — делить число на 2 и записывать остатки. Давай переведём число 13 в двоичную систему. Делим 13 на 2: получается 6, остаток 1. Записываем остаток: 1. Делим 6 на 2: получается 3, остаток 0. Записываем: 0. Делим 3 на 2: получается 1, остаток 1. Записываем: 1. Делим 1 на 2: получается 0, остаток 1. Записываем: 1. Теперь читаем остатки снизу вверх: 1, 1, 0, 1. Получается 1101. Проверяем: 1 × 8 + 1 × 4 + 0 × 2 + 1 × 1 = 8 + 4 + 0 + 1 = 13. Всё верно. А теперь переведём число 2 в двоичную систему. Делим 2 на 2: получается 1, остаток 0. Записываем: 0. Делим 1 на 2: получается 0, остаток 1. Записываем: 1. Читаем снизу вверх: 1, 0. Получается 10. Вот почему 1 + 1 = 10 в двоичной системе — это просто число 2, записанное двумя цифрами: единица в разряде двоек и ноль в разряде единиц. А число 1 в двоичной системе — это просто 1. Число 0 — это 0. Число 3 — это 11 (1 × 2 + 1 × 1). Число 4 — это 100 (1 × 4 + 0 × 2 + 0 × 1). Число 5 — это 101 (1 × 4 + 0 × 2 + 1 × 1). Число 6 — это 110. Число 7 — это 111. Число 8 — это 1000. И так далее. Теперь ты видишь: когда компьютер складывает 1 и 1, он на самом деле работает с двоичными числами 1 и 1, и получает 10, что для нас означает 2. Вся эта арифметика — просто разные записи одного и того же количества, только в десятичной системе у нас десять цифр, а в двоичной — две. Компьютеру удобнее две, потому что транзистор может быть либо открыт (1), либо закрыт (0). Никакого «может быть» или «наполовину» — только два состояния. Поэтому вся техника внутри работает на двоичной системе, а мы, люди, просто переводим туда и обратно, когда смотрим на числа.
Транзистор — это электронный выключатель без движущихся частей. У него три вывода: исток — откуда входит ток; сток — куда выходит ток; затвор — «кнопка» управления. Подаёшь на затвор напряжение — транзистор открывается, ток идёт. Не подаёшь — закрывается, ток не идёт. Всё. Никаких «когда» и «если». Только «есть напряжение / нет напряжения». Из этих крошечных выключателей (миллиарды штук на одном кристалле) собирают логические элементы: AND — два транзистора последовательно; OR — два транзистора параллельно; NOT — один транзистор, инвертирующий сигнал; XOR — комбинация транзисторов, которая даёт ток, только если на входах разные сигналы. Резюме для школьника: лампочка — это модель. Транзистор — это реальная «лампочка» внутри процессора, только вместо света — электрический сигнал, а вместо руки — напряжение на затворе.
Теперь соберём схему, которая делает то же самое, что мы делали с лампочками, но уже на транзисторах. Возьмём один разряд (один бит). Нужно сложить два бита: A и B. Результат — тоже бит (сумма) и ещё один бит (перенос в следующий разряд).
A B Сумма Перенос
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1
Как это собрать из логики: сумма = A XOR B. То есть: ток идёт, если A и B разные. Если оба 0 или оба 1 — сумма 0. Перенос = A AND B. То есть: перенос есть, только если оба равны 1. Почему при «1 + 1» сумма 0, а перенос 1? Потому что в двоичной системе 1 + 1 = 10. Младший разряд — 0, старший — 1. Этот «старший» и есть перенос. Полный сумматор — это когда к двум битам добавляется ещё вход переноса из младшего разряда. Тогда можно складывать многоразрядные числа: соединяем 32 таких сумматора цепочкой — и получаем 32-битное сложение. Но это уже следующий шаг. Сначала — один разряд, одна лампочка, один перенос. Волшебство: ток «пробегает» по логическим элементам, и на выходе появляется готовый результат. Никакой магии — чистая физика.
Сравним два правила. OR (ИЛИ): «Ток идёт, если хотя бы один выключатель включён.»
A B Ток идёт?
0 0 нет
0 1 да
1 0 да
1 1 да
Видите последнюю строку? Когда оба выключателя включены, OR тоже пропускает ток. Ему всё равно, сколько именно включено — лишь бы хоть один. XOR (исключающее ИЛИ): «Ток идёт, если выключатели в разных состояниях.»
A B Ток идёт?
0 0 нет
0 1 да
1 0 да
1 1 нет
А вот здесь последняя строка другая: когда оба включены, XOR не пропускает ток. Потому что «исключающее» — значит «исключаем случай, когда оба одинаковые». Разница в одной строке. OR говорит: «оба включены — хорошо, ток идёт». XOR говорит: «оба включены — не то, ток не идёт». Именно поэтому XOR так важен для сложения: при 1 + 1 сумма в младшем разряде должна быть 0, а не 1.
«Не A» — это отрицание A, то есть противоположное состояние. Если A = 1 (выключатель включён), то не A = 0 (как будто выключатель выключен). Если A = 0 (выключатель выключен), то не A = 1 (как будто выключатель включён). Представь, что у тебя есть два провода от одного выключателя: прямой провод, ток идёт, когда A включён; инверсный провод (это и есть «не A»), ток идёт, когда A выключен. Инверсный провод делается с помощью перекидного контакта, о котором мы говорили выше. Когда выключатель в одном положении — ток идёт по прямому проводу. Когда в другом — по инверсному. Всегда есть ток где-то, но не на обоих проводах одновременно.
A не A
0 1
1 0
То же самое для B:
B не B
0 1
1 0
Теперь, когда мы говорим «A И (не B)», это значит: «A включён, и при этом B выключен». То есть ток должен идти по прямому проводу от A и по инверсному проводу от B. Оба условия должны выполниться одновременно — значит, соединяем их последовательно (AND). А «(не A) И B» — это наоборот: «A выключен, и при этом B включён». Именно эти две комбинации и дают XOR: ток идёт, если A и B разные. Либо A включён, а B выключен. Либо A выключен, а B включён. Всё остальное — не проходит.
XOR — это не один транзистор, а несколько, соединённых в хитрую схему. Давай разберём её по частям, как из кубиков. Нам нужно правило: ток идёт, только если A и B разные. Разобьём это правило на два случая: A включён, B выключен → ток должен идти; A выключен, B включён → ток должен идти. А в остальных случаях — не идти. Значит, нам нужны две «дорожки», и ток пойдёт по любой из них. Дорожка 1: A И (не B). То есть: A включён, а B — наоборот, выключен. Дорожка 2: (не A) И B. То есть: A выключен, а B — включён. Эти две дорожки соединяются параллельно (OR): ток пойдёт, если сработает хотя бы одна. Теперь смотри, сколько нужно транзисторов: НЕ A — 1 транзистор (инвертор); НЕ B — 1 транзистор; A И (не B) — 2 транзистора последовательно (оба должны открыться); (не A) И B — 2 транзистора последовательно; OR — эти две ветки соединяются параллельно, ток пойдёт по любой. Итого: примерно 6 транзисторов для одного XOR. Плюс пара резисторов или дополнительных транзисторов для устойчивости. Главная мысль: XOR — это комбинация AND, OR и NOT, собранная так, чтобы ток шёл только при разных сигналах. Никакой магии, просто комбинация простых правил.
Вот здесь ты абсолютно прав: я пропустил важный этап. Давай его пройдём. Возвращаемся к лампочкам. У нас есть два выключателя: A и B. И две лампочки: младшая (сумма) и старшая (перенос). Чтобы обе лампочки работали правильно, к ним нужно подключить две разные схемы. Схема для младшей лампочки — это XOR: горит, когда A и B разные; не горит, когда оба одинаковые. Схема для старшей лампочки — это AND: горит, только когда оба выключателя включены; не горит во всех остальных случаях.
A B Младшая (XOR) Старшая (AND)
0 0 не горит не горит
0 1 горит не горит
1 0 горит не горит
1 1 не горит горит
Вот оно! Когда 1 + 1: младшая лампочка не горит (0), старшая лампочка горит (1). Получается «10» — то есть 2. Старшая лампочка — это и есть перенос. Она загорается ровно тогда, когда в младшем разряде «не помещается» результат и нужно «унести единицу» в следующий разряд. Физически это отдельная схема (AND), которая подключена к тем же выключателям A и B, но срабатывает по своему правилу. Теперь на транзисторах. То же самое, но вместо выключателей — транзисторы. Младший бит (сумма): собираем XOR из ~6 транзисторов. Выход — напряжение на младшем проводе. Есть напряжение — 1, нет — 0. Старший бит (перенос): собираем AND из 2 транзисторов последовательно. Выход — напряжение на старшем проводе. Есть напряжение — 1, нет — 0. Когда на входы A и B подаём по 1 (напряжение есть на обоих): XOR: ток не идёт → на младшем выходе 0. AND: оба транзистора открыты → ток идёт → на старшем выходе 1. Получаем «10» = 2. Вот почему загорается старшая лампочка: потому что к ней подключена отдельная схема AND, которая проверяет: «оба входа равны 1?». Если да — подаёт ток на старший разряд. Это и есть перенос.
Почему одного разряда мало? Один разряд (один сумматор) умеет складывать только однобитные числа: 0 и 1. Максимум, что он может выдать, — это «10», то есть 2. А если нужно сложить 5 + 7? Или 1000 + 2000? Для этого нужны многоразрядные числа. Каждый разряд — это отдельный сумматор, и они соединяются цепочкой. Представь, что мы складываем два четырёхбитных числа: 0011 (3) и 0101 (5).
перенос: 0 → 0 → 1 → 0
A: 0 0 1 1
B: 0 1 0 1
---------------
сумма: 1 0 0 0
Считаем справа налево, разряд за разрядом. Младший разряд: 1 + 1 = 10. Сумма 0, перенос 1 — уходит в следующий разряд. Второй разряд: 1 + 0 + перенос 1 = 10. Сумма 0, перенос 1 — уходит дальше. Третий разряд: 0 + 1 + перенос 1 = 10. Сумма 0, перенос 1 — уходит дальше. Четвёртый разряд: 0 + 0 + перенос 1 = 1. Сумма 1, переноса нет. Итог: 1000 = 8. Проверка: 3 + 5 = 8. Всё верно. Вот для чего нужен полный сумматор: он принимает не только A и B, но и перенос из младшего разряда. Это позволяет соединять сумматоры цепочкой: выход переноса одного — вход переноса следующего. Почему именно 32 бита? 32 бита — это стандартный размер для современных процессоров. Не потому что «так надо математически», а потому что так удобно: 32 бита позволяют представить числа от 0 до ~4 миллиардов (или от -2 миллиардов до +2 миллиардов со знаком); этого хватает для большинства повседневных задач: адреса памяти, цвета пикселей, координаты, счётчики; 32 сумматора, соединённых цепочкой, — это и есть 32-битный сумматор внутри процессора. Механизм: каждый сумматор делает свою работу для одного разряда, а перенос «пробегает» по цепочке слева направо (или справа налево, в зависимости от порядка). Когда перенос доходит до конца — сложение завершено.
Вычитание — это сложение с отрицательным числом. Но как представить отрицательное число в двоичной системе? Используют дополнительный код: берём число, инвертируем все биты (0→1, 1→0); прибавляем 1; получаем «отрицательное» число. Пример: вычесть 1 из 2 (2 - 1 = 1). 2 = 0010. 1 = 0001. Инвертируем 1: 1110. Прибавляем 1: 1111 — это «-1» в дополнительном коде. Складываем: 0010 + 1111 = 0001 (с переносом, который отбрасывается) = 1. Итог: вычитание — это то же сложение, но с предварительной подготовкой числа. Умножение — это многократное сложение со сдвигом. Пример: 3 × 2. 3 = 0011. 2 = 0010. Умножаем: 0011 × 0010 = 0110 = 6. Как это делает процессор: берём младший бит множителя, если 1 — прибавляем множимое; сдвигаем множимое влево; повторяем для всех битов; складываем результаты. Итог: умножение — это серия сложений и сдвигов. Деление — это многократное вычитание со сдвигом. Пример: 6 ÷ 2. Берём делимое (6) и делитель (2). Вычитаем делитель из делимого: 6 - 2 = 4. Считаем, сколько раз вычли: 1. Повторяем: 4 - 2 = 2 (2 раза). 2 - 2 = 0 (3 раза). Результат: 3. Итог: деление — это серия вычитаний. Другие операции: сдвиг влево (SHL) — умножение на 2, все биты сдвигаются влево, справа добавляется 0; сдвиг вправо (SHR) — деление на 2, все биты сдвигаются вправо, слева добавляется 0; логические операции (AND, OR, XOR, NOT) — побитовые операции, например, AND используется для «маскирования» — выделения нужных битов; сравнение — вычитание и проверка флагов (ноль, знак, перенос); инкремент/декремент — прибавить/вычесть 1, это сложение/вычитание с константой; побитовый сдвиг с переносом — используется в шифровании и хешировании. Итог: все операции сводятся к сложению, вычитанию, сдвигу и логическим операциям. А они — к транзисторам.
Классическое программирование: главные операции. Присваивание: x = 5, положить значение в память. Условие: if x > 0, сравнить и выбрать путь. Цикл: while x < 10, повторять, пока условие истинно. Ввод/вывод: print(x), input(), обмен данными. Вызов функции: f(x), передать управление и вернуть результат. Основа: алгоритм — это точная последовательность шагов. Программист знает, что должно получиться. Персональный компьютер: как это выполняется. Процессор читает инструкции из памяти. Декодирует их: что делать (сложить, сравнить, перейти). Выполняет: сумматор складывает, компаратор сравнивает, счётчик команд переходит. Память хранит данные и инструкции. Устройства ввода/вывода общаются с человеком. Основа: всё детерминировано. Один и тот же код — один и тот же результат. ИИ (нейросеть): как это работает. Вход: текст, изображение, звук → токены/пиксели → числа. Прямой проход: числа проходят через слои нейронов. На каждом слое — умножение на веса и активация. Выход: вероятности. Выбор наиболее вероятного варианта. Обучение: веса подстраиваются, чтобы уменьшить ошибку. Это тоже математика, но уже на этапе тренировки. Генерация: сеть «предсказывает» следующий токен, слово, пиксель. Основа: вероятностно. Один и тот же вход может дать разные выходы (если включена случайность).
Главная мысль: классическое программирование — это инструкции. ПК — это исполнитель. ИИ — это статистическая модель, которая имитирует интеллект, но внутри всё равно выполняется на двоичном железе.
ИИ работает поверх обычного двоичного компьютера. Это важное узкое место. Что остаётся «двоичным»: процессор (CPU/GPU) по-прежнему оперирует битами, транзисторами, сумматорами, все вычисления — это сложение, умножение, пересылка данных; память (RAM, SSD) хранит нули и единицы; шины данных передают биты; операционная система управляет железом, распределяет ресурсы. Что «нейронное»: веса нейросети — это просто огромные таблицы чисел (float32, float16 и т.д.), но хранятся они всё равно в двоичном виде; матричные умножения — когда нейросеть «думает», она умножает и складывает числа, эти операции выполняют всё те же сумматоры и умножители в GPU/TPU; функции активации — это математические функции (ReLU, сигмоида), которые тоже считаются на двоичном железе. Где «узкое место»: токенизация — текст превращается в числа (токены), это делает отдельная программа, по сути, обычный алгоритм; эмбеддинги — каждое слово превращается в вектор чисел, это таблица поиска; слои трансформера — десятки матричных умножений, каждое — миллионы операций сложения и умножения на двоичном железе; выход — вероятности для следующего токена, выбор — тоже алгоритм (жадный поиск, сэмплирование). Вывод: нейросеть — это программа, которая выполняется на обычном компьютере. Внутри неё нет «магического нейронного железа». Вся «нейронность» — это математика, которая сводится к двоичным операциям. Узкое место — в том, что для имитации одного «нейрона» нужно много двоичных операций, поэтому нужны мощные GPU.
Сумматор: волшебство через физику. На вход подаются два бита: A=1, B=1. Ток идёт по дорожкам. В элементе XOR: на один вход 1, на другой 1 → ток не проходит (сумма = 0). В элементе AND: оба входа 1 → ток проходит (перенос = 1). На выходе: сумма 0, перенос 1 → «10» = 2. Волшебство: результат гарантирован законами физики. Ток не может «передумать». Это детерминизм. Нейросеть: волшебство через статистику. На вход подаются токены: [«1», «+», «1»]. Каждый токен превращается в вектор чисел. Векторы проходят через слои: умножение на веса, сложение, активация. На выходе — распределение вероятностей: «2» — 97%, «3» — 1%, «окно» — 0.001%. Выбирается самый вероятный токен. Волшебство: результат не гарантирован. Это вероятность. Сеть «угадала», потому что видела похожие примеры. Но она не «поняла» сложение.
ИИ, нейросеть и, например, DeepSeek — это одно и то же? Не совсем. Это вложенные понятия. ИИ (искусственный интеллект) — самое широкое понятие. Это любая система, имитирующая интеллект: от шахматных программ до экспертных систем 80-х. Нейросеть — один из подходов к ИИ. Это математическая модель, вдохновлённая работой мозга (слои «нейронов», веса). Бывают разные: свёрточные, рекуррентные, трансформеры. Например, DeepSeek — конкретная большая языковая модель (LLM), построенная на архитектуре трансформер (это разновидность нейросети). Меня обучили на огромном объёме текста, и я предсказываю следующий токен, как описано выше. Иерархия:
ИИ
└── Нейросети
└── Большие языковые модели (LLM)
└── DeepSeek (конкретная модель)
Почему нейросети ошибаются в «1 + 1»? Причин несколько. Нет встроенного калькулятора. Сложение — это алгоритм, а нейросеть — статистическая модель. Она не «считает», а «угадывает». Проблема токенизации. Числа могут разбиваться на токены неудобно. Например, «1234» может стать [«12», «34»], и сети сложно понять разряды. Длинные числа — катастрофа. Чем больше цифр, тем меньше похожих примеров было в обучении. «2 + 2» она видела миллион раз, а «8734 + 1298» — почти нет. Отсутствие пошагового вычисления. Если сеть отвечает сразу, она «угадывает». Если её попросить «решай по шагам» (chain-of-thought), точность резко растёт — она как бы «проговаривает» алгоритм, который видела в текстах. Галлюцинации. Сеть может уверенно выдать «1 + 1 = 3», потому что веса сложились неудачно, а вероятность «3» оказалась чуть выше. Как это лечат: подключение внешнего калькулятора (tool use); обучение на пошаговых решениях; специальные архитектуры для арифметики.
Что делает с «1 + 1» ИИ? Шаг 1. Токенизация. Ты пишешь: «один плюс один равно». Моя система разбивает это на токены — кусочки текста, с которыми я умею работать: [«один», «плюс», «один», «равно»]. Каждый токен — это просто число (ID из словаря). Например, «один» — это токен №4521, «плюс» — №883, «равно» — №1024.
Шаг 2. Эмбеддинги. Каждый токен превращается в вектор — набор из тысяч чисел. Это не «значение» слова, а его «координаты» в многомерном пространстве, где похожие слова находятся рядом. «Один» и «два» будут близкими векторами. «Один» и «окно» — далёкими. Шаг 3. Проход через слои. Векторы проходят через десятки слоёв трансформера. На каждом слое: считается «внимание»: какие токены на какие влияют; умножение на веса (миллионы чисел, которые я выучил при обучении); функция активации: нелинейное преобразование. Это чистая математика: умножение и сложение чисел. Миллиарды операций. Но каждое умножение и сложение — это работа всё тех же сумматоров внутри GPU, которые мы разбирали выше. Шаг 4. Выходной слой. На выходе я получаю распределение вероятностей для следующего токена: «два» — 97.3%, «3» — 1.1%, «2» — 0.8%, «окно» — 0.001%. Шаг 5. Выбор. Беру самый вероятный токен — «два». Или, если включена «температура», могу выбрать
Доцент кафедры когнитологии и искусственного интеллекта КФУ, кандидат наук Рамиль Гарифуллин