30566 = 0111011101100110
=
1132 = 11101110 11001100
Произошел перенос из 14-го разряда; из 15-го разряда переноса нет. Результат неправильный, так как имеется переполнение – значение числа получилось больше, чем то, которое может иметь 16-битное число со знаком (+32 767).
Пример
-30566 = 10001000 10011010
+
-04875 = 11101100 11110101
=
-35441 = 01110101 10001111
Произошел перенос из 15-го разряда, из 14-го разряда нет переноса. Результат неправильный, так как вместо отрицательного числа получилось положительное (в старшем бите находится 0).
Пример
-4875 = 11101100 11110101
+
-4875 = 11101100 11110101
=
09750 = 11011001 11101010
Есть переносы из 14 и 15-го разрядов. Результат правильный.
Таким образом, мы исследовали все случаи и выяснили, что ситуация переполнения (установка флага OF в 1) происходит при переносе:
1) из 14-го разряда (для положительных чисел со знаком);
2) из 15-го разряда (для отрицательных чисел).
И наоборот, переполнения не происходит (т. е. флаг OF сбрасывается в 0), если есть перенос из обоих разрядов или перенос отсутствует в обоих разрядах.
Итак, переполнение регистрируется с помощью флага переполнения of. Дополнительно к флагу of при переносе из старшего разряда устанавливается в 1 и флаг переноса CF Так как микропроцессор не знает о существовании чисел со знаком и без знака, то вся ответственность за правильность действий с получившимися числами ложится на программиста. Проанализировать флаги CF и OF можно командами условного перехода JC\JNC и JO\JNO соответственно.
Что же касается команд сложения чисел со знаком, то они те же, что и для чисел без знака.
Как и при анализе операции сложения, порассуждаем над сутью процессов, происходящих при выполнении операции вычитания. Если уменьшаемое больше вычитаемого, то проблем нет, – разность положительна, результат верен. Если уменьшаемое меньше вычитаемого, возникает проблема: результат меньше 0, а это уже число со знаком. В этом случае результат необходимо завернуть. Что это означает? При обычном вычитании (в столбик) делают заем 1 из старшего разряда. Микропроцессор поступает аналогично, т. е. занимает 1 из разряда, следующего за старшим, в разрядной сетке операнда. Поясним на примере.
Пример
05 = 00000000 00000101
-10 = 00000000 00001010
Для того чтобы произвести вычитание, произведем
воображаемый заем из старшего разряда:
100000000 00000101
-
00000000 00001010
=
11111111 11111011
Тем самым, по сути, выполняется действие
(65 536 + 5) – 10 = 65 531
0 здесь как бы эквивалентен числу 65536. Результат, конечно, неверен, но микропроцессор считает, что все нормально, хотя факт заема единицы он фиксирует установкой флага переноса cf. Но посмотрите еще раз внимательно на результат операции вычитания. Это же -5 в дополнительном коде! Проведем эксперимент: представим разность в виде суммы 5 + (-10).
Пример
5 = 00000000 00000101
+
(-10)= 11111111 11110110
=
11111111 11111011
т. е. мы получили тот же результат, что и в предыдущем примере.
Таким образом, после команды вычитания чисел без знака нужно анализировать состояние флага СЕ Если он установлен в 1, то это говорит о том, что произошел заем из старшего разряда и результат получился в дополнительном коде.
Аналогично командам сложения группа команд вычитания состоит из минимально возможного набора. Эти команды выполняют вычитание по алгоритмам, которые мы сейчас рассматриваем, а учет особых ситуаций должен производиться самим программистом. К командам вычитания относятся следующие:
1) dec операнд – операция декремента, т. е. уменьшения значения операнда на 1;
2) sub операнд_1, операнд_2 – команда вычитания; ее принцип действия: операнд_1 = операнд_1 – операнд_2;
3) sbb операнд_1, операнд_2 – команда вычитания с учетом заема (флага ci): операнд_1 = операнд_1 – операнд_2 – значение_сГ.
Как видите, среди команд вычитания есть команда sbb, учитывающая флаг переноса cf. Эта команда подобна adc, но теперь уже флаг cf исполняет роль индикатора заема 1 из старшего разряда при вычитании чисел.
Здесь все несколько сложнее. Микропроцессору незачем иметь два устройства – сложения и вычитания. Достаточно наличия только одного – устройства сложения. Но для вычитания способом сложения чисел со знаком в дополнительном коде необходимо представлять оба операнда – и уменьшаемое, и вычитаемое. Результат тоже нужно рассматривать как значение в дополнительном коде. Но здесь возникают сложности. Прежде всего они связаны с тем, что старший бит операнда рассматривается как знаковый. Рассмотрим пример вычитания 45 – (-127).
Пример
Вычитание чисел со знаком 1
45 = 0010 1101
-
-127 = 1000 0001
=
-44 = 1010 1100