- •4.13 Особенности арифметических операций c двоичными данными.
- •Многословное сложение
- •Word1a 0123
- •Буззнаковые и знаковые данные
- •Беззнаковое Знаковое
- •4.13.2 Умножение
- •ДоАн alПослеAx
- •Знаковое умножение: команда imul
- •C10mul endp
- •Многословноe умножение
- •Сдвиг влево на 4 бита
- •4.13.3 Деление
- •До ax После ан al
- •Беззнаковое деление: команда div
- •Знаковое деление: команда idiv
- •Переполнения и прерывания
- •Деление вычитанием
- •4.13.4 Преобразование знака
C10mul endp
; Пример умножения IMUL:
D10 IMUL PROC
MOV AL, BYTE1 ;Байт * байт
IMUL BYTE2 ;произведение в AX
MOV AX,WORD1 ;Слово * слово
IMUL WORD2 ;произвед, в DX:AX
MOV AL,BYTE1 ;Байт * слово
CBW ;расшир. множимого в АН
IMUL WORD1 ;произвед, в DX:AX
RET
D10 IMUL ENDP
CODESG ENDS
END BEGIN
Рис.4.26. Беззнаковое и знаковое умножение
Первый пример команды IMUL перемножает 80H (отрицательное число) на 40H (положительное число). Произведение Е000Hполучается в регистре AX. Используя те же данные, команда MUL дает в результате 2000(12810 (80H) * 6410 (40H) = 819210 или 2000H, а команда IMUL дополняет результат знаковыми единицами и получает Е000H), так что можно видеть разницу в использовании команд MUL и IMUL. Команда MUL рассматривает 80H как +128, а команда IMUL - как -128. В результате умножения -128 на +64 получается -8192 или шестнадцатиричное Е000. (Попробуйте преобразовать Е000 в десятичный формат.)
Второй пример команды IMUL перемножает 8000H (отрицательное значение) на 2000Н (положительное значение). Произведение F0000000 получается в регистрах DX:AX и представляет собой отрицательное значение.
Третий пример команды IMUL перед умножением выполняет расширение байта BYTE1 до размеров слова в регистре AX. Так как значения предполагаются знаковые, то в примере используется команда CBW для перевода левого знакового бита в регистр АН:
шестнадцатиричное 80 в регистре AL превращается в FF80 в регистре AX. Поскольку множитель в слове WORD1 имеет также отрицательное значение, то произведение будет положительным. В самом деле, 00400000Н в регистрах DX:AX - такой же результат, как и в случае умножения командой MUL, которая предполагала положительные сомножители.
Таким образом, если множимое и множитель имеют одинаковый знаковый бит, то команды MUL и IMUL генерируют одинаковый результат. Но если сомножители имеют разные знаковые биты, то команда MUL вырабатывает положительный результат умножения, а команда IMUL - отрицательный.
Можно обнаружить это, используя трассировкe примеров.
Повышение эффективности умножения.
При умножении на степень числа 2 (2,4,8 и т.д.) более эффективен сдвиг влево на требуемое число битов. Сдвиг более чем на 1 требует загрузки счетчика сдвига в регистр CL. В следующих примерах предположим, что множимое находится в регистре AL или AX:
Умножение на 2:
SHL AL,1
Умножение на 8:
MOV CL,3
SHL AX,CL
Многословноe умножение
Обычно умножение бывает двух типов: умножение байта на байт и умножение слова на слово. Как было показано, максимальное знаковое значение в слове + 32767. Умножение больших чисел требует выполнения некоторых дополнительных действий. Рассматриваемый подход предполагает умножение каждого слова отдельно и затем сложение полученных результатов.
Рассмотрим следующее умножение в десятичном формате:
1365
x12
2730
1365
16380
Представим, что Десятичная арифметика может умножать только двузначные числа. Тогда можно умножить 13 и 65 на 12 раздельно:
13 65
x12 x12
26 130
13 65
156 780
Теперь сложим полученные произведения, но поскольку число 13 представляло сотни, то первое произведение в действительности будет 15600:
15600 +780 =16380
Ассемблерная программа использует аналогичную технику, за исключением того, что данные имеют размерность двойных слов (четыре цифры) в шестнадцатеричном формате.
Умножение двойного слова на слово. Процедура E10XMUL на рис. 4.27 умножает двойное слово на слово.
Множимое MULTCND состоит из двух слов, содержащих соответственно 3206Н и 2521Н. Определение данных в виде двух слов (DW) вместо двойного слова (DD) обусловлено необходимостью правильной адресации для команд MOV, пересылающих слова в регистр AX.
Множитель MULTPLR содержит 6400Н.
Область для записи произведения PRODUCT состоит из трех слов.
Первая команда MUL перемножает MULTPLR и правое слово поля MULTCND; произведение 0Е80 Е400 записывается в PRODUCT+2 и PRODUCT+4.
Вторая команда MUL перемножает MULTPLR и левое слово поля MULTCND, получая в результате 138А 5800.
Далее выполняется сложение двух произведений следующим образом:
Произведение 1: 0000 0Е80 Е400 Произведение 2: 138А 5800 Результат: 138А 6680 Е400
Так как первая команда ADD может выработать перенос, то второе сложение выполняется командой сложения с переносом ADC (ADd with Carry). В силу обратного представления байтов в словах в процессорах 8086/8088 область PRODUCT в действительности будет содержать значение 8А13 8066 00Е4. Программа предполагает, что первое слово в области PRODUCT имеет начальное значение 0000.
Умножение двойного слова на двойное слово.
Умножение двух двойных слов включает следующие четыре операции умножения:
Множимое Множитель
слово 2 х слово 2
слово 2 х слово 1
слово 1 х слово 2
слово 1 х слово 1
TITLE EXDWMUL - Умножение двойных слов
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
MULTCND DW 3206H ;Элементы данных
DW 2521H
MULTPLR DW 6400Н
DW 0A26H
PRODUCT DW 0
DW 0
DW 0
DW 0
MAIN PROC NEAR ;Основная процедура
CALL E10XMUL ;Вызвать 1-е умножение
CALL Z10ZERO ;Очистить произведение
CALL E10XMUL ;Вызвать 2-е умножение
RET
MAIN ENDP
; Умножение дв.слова на слово:
E10XMUL PROC
MOV AX,MULTCND+2 ;Умнож. прав. cл.
MUL MULTPLR ;множимого
MOV PRODUCT+4,AX ;3аписать произв.
MOV PRODUCT+2,DX
MOV AX,MULTCND ;Умножить лев. cл.
MUL MULTPLR ;множимого
ADD PRODUCT+2,AX ;Сложить с полученным ранее
ADC PRODUCT, DX
RET
E10XMUL ENDP
; Перемножение двух двойных слов:
F10XMUL PROC
MOV AX,MULTCND+2 Слово-2 множимого
MUL MULTPLR+2 * слово-2 множителя
MOV PRODUCT+6,AX Сохранить рез.
MOV PRODUCT+4,AX
MOV AX,MULTCND+2 Слово-2 множимого
MUL MULTPLR * слово-1 множителя
ADD PRODUCT+4,AX Сложить с пред.
ADC PRODUCT+6,AX
ADC PRODUCT,00 Прибавить перенос
MOV AX,MULTCND Слово-1 множимого
MUL MULTPLR+2 * Слово-2 множителя
ADC PRODUCT+4,AX Сложить с пред.
ADC PROOUCT+6,DX
ADC PRODUCT,00 Прибавить перенос
MOV AX,MULTCND Слово-1 множимого
MUL MULTPLR * слово-1 множителя
ADD PRODUCT+2,AX Сложить с пред.
ADC PRODUCT, DX,
RET
F10XMUL ENDP
; Очистка области результата:
Z10XMUL PROC
MOV PRODUCT,0000
MOV PRODUCT+2,0000
MOV PRODUCT+4,0000
MOV PRODUCT+6,0000
RET
Z10XMUL ENDP
CODESG ENDS
END BEGIN
Рис. 4.27. Многословное умножение
Каждое произведение в регистровой паре DX:AX складывается с соответствующим словом в окончательном результате. Пример такого умножения приведен в процедуре F10XMUL на рис. 4.27. Множимое MULTCND содержит 3206 2521, множитель MULTPLR -6400 0A26. Результат заносится в область PRODUCT, состоящую из четырех слов.
Хотя логика умножения двойных слов аналогична умножению двойного слова на слово, имеется одна особенность. После пары команд сложения ADD/ADC используется еще одна команда ADC, которая прибавляет 0 к значению в поле PRODUCT. Это необходимо потому, что первая команда ADC сама может вызвать перенос, который последующие команды могут стереть. Поэтому вторая команда ADC прибавит 0, если переноса нет, и прибавит 1, если перенос есть.
Финальная пара команд ADD/ADC не требует дополнительной команды ADC, так как область PRODUCT достаточно велика для генерации окончательного результата и переноса на последнем этапе не будет.
Окончательный результат 138А 687С 8Е5С ССЕ6 получится а поле PRODUCT в обратной последовательности байтов в словах.
СДВИГ РЕГИСТРОВОЙ ПАРЫ EDX:EAX
Следующая подпрограмма может быть полезна для сдвига содержимого регистровой пары EDX:EAX вправо или влево. Можно придумать более эффективный метод, но данный пример представляет общий подход для любого числа циклов (и соответственно сдвигов) в регистре CX. Заметьте, что сдвиг единичного бита за разрядную сетку устанавливает флаг переноса.