Найти в Дзене
IT Еxtra

Как работает компьютер? Часть 29. Вычитание и отрицательные числа — как компьютер учится работать с минусами

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

Чтобы понять, как компьютер справляется с вычитанием, нам нужно вспомнить школьную арифметику. Вычитание — это по сути сложение с отрицательным числом. Например, 7 – 3 = то же самое, что 7 + (–3). Значит, если компьютер сможет работать с отрицательными числами, то отдельное устройство для вычитания ему не понадобится: достаточно только сумматора.

Здесь мы подходим к одной из самых интересных идей в компьютерной арифметике — представлению чисел в дополнительном коде.

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

Представим, что у нас есть байт (8 бит). С помощью 8 бит можно закодировать числа от 0 до 255. Но если мы хотим хранить ещё и отрицательные числа, то делим этот диапазон пополам. В итоге: положительные числа и ноль: от 00000000 до 01111111 (0…127), отрицательные числа: от 10000000 до 11111111 (–128…–1).

Таким образом, старший бит (левый) становится «знаковым»: если он равен 0 — число положительное, если 1 — отрицательное.

А теперь — главный фокус. Чтобы получить отрицательное число, используется дополнительный код. Алгоритм очень простой:

  1. Берём двоичное представление положительного числа.
  2. Инвертируем все биты (заменяем 0 на 1, а 1 на 0).
  3. Прибавляем к результату единицу.

Например, как записать –5 в 8-битной системе?

  1. Сначала пишем +5: 00000101.
  2. Инвертируем: 11111010.
  3. Прибавляем единицу: 11111011.

Именно эта комбинация битов и будет означать «–5».

В чём прелесть этого метода? В том, что сложение отрицательных чисел работает автоматически. Если мы захотим посчитать 7 + (–5), то просто сложим 00000111 и 11111011, получим 00000010, что равно 2. Сумматор даже не знает, что он работал с отрицательным числом, — для него это просто биты.

Теперь вернёмся к нашей задаче: как выполнить вычитание? Допустим, нам нужно вычислить 9 – 4. Мы можем записать это как 9 + (–4). То есть задача сводится к сложению положительного числа и отрицательного.

  1. Возьмём 9 = 00001001.
  2. Теперь найдём –4: сначала +4 = 00000100, инвертируем = 11111011, прибавляем 1 = 11111100.
  3. Теперь складываем: 00001001 + 11111100 = 00000101

Результат — 5. Всё работает!

Таким образом, отдельного устройства для вычитания не нужно. Сумматор и так умеет вычитать, если мы правильно представим отрицательные числа.

Попробуем что-то посложнее: –3 + (–2).

  1. Запишем –3: сначала 00000011, инвертируем = 11111100, прибавляем 1 = 11111101.
  2. Запишем –2: сначала 00000010, инвертируем = 11111101, прибавляем 1 = 11111110.
  3. Теперь складываем: 11111101 + 11111110 = 111111011

Так как у нас 8 бит, лишний девятый бит (перенос) отбрасываем. Получаем: 11111011. Это дополнительный код числа –5. Проверка прошла успешно!

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

Например, в 8-битной системе:

127 + 1 = 10000000. Это вовсе не 128, а –128. Компьютер просто не может хранить числа больше 127, поэтому результат «переворачивается». Это нужно помнить, потому что в реальных программах переполнение может привести к ошибкам.

Теперь мы видим, что процессор не только умеет складывать, но и вычитать, и работать с отрицательными числами. Всё это делается с помощью одного и того же устройства — многобитного сумматора. Именно так устроена арифметика в арифметико-логическом устройстве (АЛУ).

АЛУ процессора умеет выполнять операции: сложение, вычитание, сравнение, иногда умножение и деление. Но все они так или иначе основаны на идее сумматора и представления чисел в дополнительном коде. То есть сейчас мы фактически построили основу вычислительной части процессора.

Мы сделали большой шаг вперёд. Мы узнали, что вычитание можно выполнить с помощью того же самого сумматора, если представить отрицательные числа в дополнительном коде. Мы разобрали, как кодируются отрицательные числа, как выполняется операция вычитания и почему иногда возникает переполнение. Теперь у нас есть устройство, которое может работать с числами и в плюс, и в минус.

Спасибо за внимание!