Мы уже научили компьютер складывать числа при помощи многобитного сумматора. Но этого явно недостаточно, ведь любая реальная задача требует не только сложения, но и вычитания. На первый взгляд кажется, что нужно построить ещё одно устройство — «вычитатель». Но инженеры пошли умнее: оказалось, что вычитание можно выполнить с помощью тех же сумматоров, просто по-другому представив числа.
Чтобы понять, как компьютер справляется с вычитанием, нам нужно вспомнить школьную арифметику. Вычитание — это по сути сложение с отрицательным числом. Например, 7 – 3 = то же самое, что 7 + (–3). Значит, если компьютер сможет работать с отрицательными числами, то отдельное устройство для вычитания ему не понадобится: достаточно только сумматора.
Здесь мы подходим к одной из самых интересных идей в компьютерной арифметике — представлению чисел в дополнительном коде.
В обычной жизни мы пишем минус перед числом: –5. Но компьютер работает только с нулями и единицами, никаких «минусов» в электричестве не существует. Поэтому инженеры придумали систему, в которой отрицательные числа кодируются особым образом.
Представим, что у нас есть байт (8 бит). С помощью 8 бит можно закодировать числа от 0 до 255. Но если мы хотим хранить ещё и отрицательные числа, то делим этот диапазон пополам. В итоге: положительные числа и ноль: от 00000000 до 01111111 (0…127), отрицательные числа: от 10000000 до 11111111 (–128…–1).
Таким образом, старший бит (левый) становится «знаковым»: если он равен 0 — число положительное, если 1 — отрицательное.
А теперь — главный фокус. Чтобы получить отрицательное число, используется дополнительный код. Алгоритм очень простой:
- Берём двоичное представление положительного числа.
- Инвертируем все биты (заменяем 0 на 1, а 1 на 0).
- Прибавляем к результату единицу.
Например, как записать –5 в 8-битной системе?
- Сначала пишем +5: 00000101.
- Инвертируем: 11111010.
- Прибавляем единицу: 11111011.
Именно эта комбинация битов и будет означать «–5».
В чём прелесть этого метода? В том, что сложение отрицательных чисел работает автоматически. Если мы захотим посчитать 7 + (–5), то просто сложим 00000111 и 11111011, получим 00000010, что равно 2. Сумматор даже не знает, что он работал с отрицательным числом, — для него это просто биты.
Теперь вернёмся к нашей задаче: как выполнить вычитание? Допустим, нам нужно вычислить 9 – 4. Мы можем записать это как 9 + (–4). То есть задача сводится к сложению положительного числа и отрицательного.
- Возьмём 9 = 00001001.
- Теперь найдём –4: сначала +4 = 00000100, инвертируем = 11111011, прибавляем 1 = 11111100.
- Теперь складываем: 00001001 + 11111100 = 00000101
Результат — 5. Всё работает!
Таким образом, отдельного устройства для вычитания не нужно. Сумматор и так умеет вычитать, если мы правильно представим отрицательные числа.
Попробуем что-то посложнее: –3 + (–2).
- Запишем –3: сначала 00000011, инвертируем = 11111100, прибавляем 1 = 11111101.
- Запишем –2: сначала 00000010, инвертируем = 11111101, прибавляем 1 = 11111110.
- Теперь складываем: 11111101 + 11111110 = 111111011
Так как у нас 8 бит, лишний девятый бит (перенос) отбрасываем. Получаем: 11111011. Это дополнительный код числа –5. Проверка прошла успешно!
При работе с отрицательными числами может случаться интересная ситуация — переполнение. Например, если мы попробуем сложить два больших положительных числа, результат может «выйти за пределы» доступного диапазона и стать отрицательным. То же самое наоборот: при сложении двух отрицательных чисел можем неожиданно получить положительное.
Например, в 8-битной системе:
127 + 1 = 10000000. Это вовсе не 128, а –128. Компьютер просто не может хранить числа больше 127, поэтому результат «переворачивается». Это нужно помнить, потому что в реальных программах переполнение может привести к ошибкам.
Теперь мы видим, что процессор не только умеет складывать, но и вычитать, и работать с отрицательными числами. Всё это делается с помощью одного и того же устройства — многобитного сумматора. Именно так устроена арифметика в арифметико-логическом устройстве (АЛУ).
АЛУ процессора умеет выполнять операции: сложение, вычитание, сравнение, иногда умножение и деление. Но все они так или иначе основаны на идее сумматора и представления чисел в дополнительном коде. То есть сейчас мы фактически построили основу вычислительной части процессора.
Мы сделали большой шаг вперёд. Мы узнали, что вычитание можно выполнить с помощью того же самого сумматора, если представить отрицательные числа в дополнительном коде. Мы разобрали, как кодируются отрицательные числа, как выполняется операция вычитания и почему иногда возникает переполнение. Теперь у нас есть устройство, которое может работать с числами и в плюс, и в минус.
Спасибо за внимание!