Информатика и информационные технологии: конспект лекций
Шрифт:
Пример
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
Судя по знаковому разряду, результат получился отрицательный, что, в свою очередь, говорит о том, что число нужно рассматривать как дополнение, равное —44. Правильный результат должен быть равен 172. Здесь мы, как и в случае знакового сложения, встретились с переполнением мантиссы, когда значащий разряд числа изменил знаковый разряд операнда. Отследить такую ситуацию можно по содержимому флага переполнения of. Его установка в 1 говорит о том, что результат вышел за диапазон представления знаковых чисел (т. е. изменился старший бит) для операнда данного размера, и программист должен предусмотреть действия по корректировке результата.
Пример
Вычитание чисел со знаком 2
– 45–45 = -45 + (-45)= -90.
– 45 = 11010011
+
– 45 = 11010011
=
– 90 = 1010 0110
Здесь все нормально, флаг переполнения of сброшен в 0, а 1 в знаковом разряде говорит о том, что значение результата – число в дополнительном коде.
Вычитание и сложение операндов большой размерности
Если вы заметили, команды сложения и вычитания работают с операндами фиксированной размерности: 8, 16, 32 бит. А что делать, если нужно сложить числа большей размерности, например 48 бит, используя 16-разрядные операнды? К примеру, сложим два 48-разрядных числа:
Рис. 29. Сложение операндов большой размерности
На рисунке 29 по шагам показана технология сложения длинных
чисел. Видно, что процесс сложения многобайтных чисел происходит так же, как и при сложении двух чисел «в столбик», – с осуществлением при необходимости переноса 1 в старший разряд. Если нам удастся запрограммировать этот процесс, то мы значительно расширим диапазон двоичных чисел, над которыми мы сможем выполнять операции сложения и вычитания.Принцип вычитания чисел с диапазоном представления, превышающим стандартные разрядные сетки операндов, тот же, что и при сложении, т. е. используется флаг переноса cf. Нужно только представлять себе процесс вычитания в столбик и правильно комбинировать команды микропроцессора с командой sbb.
В завершение обсуждения команд сложения и вычитания отметим, что кроме флагов cf и of в регистре eflags есть еще несколько флагов, которые можно использовать с двоичными арифметическими командами. Речь идет о следующих флагах:
1) zf – флаг нуля, который устанавливается в 1, если результат операции равен 0, и в 1, если результат не равен 0;
2) sf – флаг знака, значение которого после арифметических операций (и не только) совпадает со значением старшего бита результата, т. е. с битом 7, 15 или 31. Таким образом, этот флаг можно использовать для операций над числами со знаком.
Умножение чисел без знака
Для умножения чисел без знака предназначена команда
mul сомножитель_1
Как видите, в команде указан всего лишь один операнд-сомножитель. Второй операнд-сомножитель_2 задан неявно. Его местоположение фиксировано и зависит от размера сомножителей. Так как в общем случае результат умножения больше, чем любой из его сомножителей, то его размер и местоположение должны быть тоже определены однозначно. Варианты размеров сомножителей и размещения второго операнда и результата приведены в таблице 10.
Из таблицы видно, что произведение состоит из двух частей и в зависимости от размера операндов размещается в двух местах – на месте сомножитель_2 (младшая часть) и в дополнительном регистре ah, dx, edx (старшая часть). Как же динамически (т. е. во время выполнения программы) узнать, что результат достаточно мал и уместился в одном регистре или что он превысил размерность регистра и старшая часть оказалась в другом регистре? Для этого привлекаются уже известные нам по предыдущему обсуждению флаги переноса cf и переполнения of:
1) если старшая часть результата нулевая, то после операции произведения флаги cf = 0 и of = 0;
2) если же эти флаги ненулевые, то это означает, что результат вышел за пределы младшей части произведения и состоит из двух частей, что и нужно учитывать при дальнейшей работе.
Умножение чисел со знаком
Для умножения чисел со знаком предназначена команда
[imul операнд_1, операнд_2, операнд_3]
Эта команда выполняется так же, как и команда mul. Отличительной особенностью команды imul является только формирование знака.