Команды сложения и вычитания
Сложение и вычитание двоичных чисел без знака
Сложение и вычитание двоичных чисел без знака осуществляется МП по правилам двоичной арифметики.
При сложении двоичных чисел без знака возможна ситуация, когда результат превышает значение, которое может быть записано в операнд данной разрядности. Например, в один байт может быть записано число не более 255, а в слово – не более 65536 (см. табл.1.3). Действительно, пусть при работе с операндами размером в байт необходимо сложить числа 251 и 12:
Полученный результат не умещается в операнд разрядностью в байт (произошел перенос единицы в старший разряд). Старшая единица отбрасывается и в качестве ответа принимается искаженная сумма (в примере 00000111B = 7D).
Для фиксирования ситуации выхода за разрядную сетку предназначен флаг переноса CF. Он устанавливается в единицу, когда произошел такой перенос, и устанавливается в ноль, когда переноса не произошло. Анализировать этот флаг можно, например, с помощью команд условного перехода JC или JNC (см. разд.9.2).
При вычитании двоичных чисел без знака в том случае, когда уменьшаемое больше или равно вычитаемого результат всегда получается корректным. Если уменьшаемое меньше вычитаемого, то результат должен быть отрицательным, что недопустимо, так как работаем с числами без знака. В этом случае при выполнении операции МП выполняет заем из старшего разряда и устанавливает флаг переноса CF. Пусть, например, необходимо вычесть из числа 3 число 9:
Результат получился неверным, однако он будет правильным, если считать, что результат получился в дополнительном коде.
При сложении и вычитании чисел без знака о корректности результата можно судить, анализируя флаг CF. Если флаг установлен в единицу, то результат операции неправильный.
Сложение и вычитания двоичных чисел со знаком
Положительные числа со знаком представляются в прямом коде, а отрицательные – в дополнительном коде (см. разд.1.6). При таком представлении складывать и вычитать числа можно по тем же алгоритмам (используя те же команды), что и числа без знака. Это основное преимущество представления отрицательных чисел в дополнительном коде. МП не делает различий между числами со знаком и числами без знака, и вся ответственность за правильность результата ложится на программиста.
Диапазоны чисел, которые можно записать в операнды определенного размера для чисел со знаком меньше чем для чисел без знака и приведены в табл.1.3.
Рассмотрим различные варианты сложения чисел со знаком, чтобы определить, как влияет поведение двух старших битов операндов (на примере операндов имеющих длину в один байт) на правильность операции:
Переносов из шестого и седьмого разрядов нет. Результат корректный.
Переносов из шестого и седьмого разрядов нет. Результат корректный.
Произошел перенос из шестого разряда, из седьмого разряда переноса не было. Результат некорректный, так как значение числа получилось больше чем то, которое может иметь число со знаком (+128). Так как старший бит результата равен 1, то его надо считать отрицательным (записанным в дополнительном коде). Подобное переполнение фиксируется установкой в единицу флага переполнения OF. Анализировать этот флаг можно, например, с помощью команд условного перехода JO или JNO (см. разд.9.2).
Произошел перенос из седьмого разряда, из шестого разряда переноса не было. Результат некорректный, так как получилось положительное число. Подобное переполнение фиксируется установкой в единицу флага переполнения OF. Флаг CF также устанавливается в единицу.
Произошел перенос из шестого и из седьмого разряда. Результат корректный (вышедшая единица все равно будет потеряна). Устанавливается в единицу флаг переноса CF, флаг переполнения OF равен нулю.
В общем случае установка флага OF происходит, когда наблюдается перенос из шестого или четырнадцатого разряда (для положительных чисел со знаком) или из седьмого или пятнадцатого разряда (для отрицательных чисел). Флаг OF сбрасывается, если перенос есть в обоих разрядах или отсутствует в обоих разрядах.
Аналогичные выкладки можно записать и для операции вычитания знаковых чисел.
При сложении и вычитании чисел со знаком о корректности результата можно судить, анализируя флаг OF. Если флаг установлен в единицу, то результат операции неправильный.
Основными командами для сложения и вычитания как чисел без знака, так и чисел со знаком являются команды ADD (от англ. ADD – складывать) и SUB (от англ. SUBtract – вычитать). Формат этих команд показан на рис.10.1.
Рис. 10.1. Формат команд ADD и SUB
Размерности операндов должны совпадать. Первым операндом может быть регистр или значение в памяти, вторым операндом может быть регистр, значение в памяти или непосредственный операнд. Результат операции оказывается на месте первого операнда (операнда-приемника). Выполнение команд оказывает влияние на состояние флагов CF, OF, ZF, SF и PF.
per1 DB 130
per2 DB 42
…
MOV AH,12
ADD AH,21
ADD AH,per1
SUB AH,per2
Вычитание и сложение операндов большой размерности
Для сложения и вычитания операндов большой размерности (более двух слов) можно пользоваться командами сложения с переносом ADC (от англ. ADd with Carry – сложить с переносом) и вычитания с заемом SBB (от англ. SuBtract with Borrow – вычесть с заемом). Эти команды в целом похожи на команды простого сложения и вычитания за одним исключением: при выполнении команды ADC к результату сложения дополнительно прибавляется значение флага переноса, при выполнении команды SBB из разности операндов дополнительно вычитается значение этого флага.
Например, сложим два 32-разрядных двоичных числа:
При сложении младших частей может появиться единица переноса, которую необходимо учесть при сложении старших частей (при сложении старших частей также может появиться единица переноса, но она уже не учитывается). Если принять, что младшая часть первого числа находится в регистре AX, его старшая часть в регистре BX, младшая часть второго числа находится в регистре CX, его старшая часть в регистре DX, то фрагмент программы для сложения чисел будет выглядеть следующим образом:
ADD AX,CX
ADC BX,DX
Подобным образом можно организовать сложение и вычитание чисел любого размера.