Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие 3000239.doc
Скачиваний:
23
Добавлен:
30.04.2022
Размер:
1.12 Mб
Скачать

3.4. Команды умножения и деления

Команды умножения

Если сложение и вычитание беззнаковых и знаковых чисел производятся по одним и тем же алгоритмам, то умножение чисел этих двух классов выполняется по разным алгоритмам, в связи с чем в ПК имеются две команды умножения:

Умножение целых без знака (multiply): MUL op

Умножение целых со знаком (integer multiply): IMUL op

В остальном эти команды действуют одинаково:

Умножение байтов: AX:=AL*op (op: r8, m8)

Умножение слов: (DX,AX):=AX*op (op: r16, m16)

Операнд op, указываемый в команде, – это лишь один из сомножителей; он может находиться в регистре или в памяти, но не может быть непосредственным операндом. Местонахождение другого сомножителя фиксировано и потому в команде не указывается явно: при умножении байтов он берется из регистра AL, а при умножении слов – из регистра АХ.

Местонахождение результата умножения также заранее известно и потому в команде явно не указывается. При этом под результат отводится в два раза больше места, чем под сомножители. Это связано с тем, что умножение n-значных чисел в общем случае дает произведение из 2n цифр, и с желанием сохранить все цифры произведения. При умножении байтов результат имеет размер слова и записывается в весь регистр АХ (в АН – старшие цифры произведения, в AL – младшие), а при умножении слов результат имеет размер двойного слова и записывается в два регистра – в регистр DX заносятся старшие цифры произведения, а в регистр АХ – младшие цифры.

Примеры:

N DB 10

MOV AL,2

MUL N ;AX=2*10=20=0014h: AH=00h, AL=14h

MOV AL,26

MUL N ;AX ;AX=26*10=260=0104h: AB=01h, AL=04h

MOV AX,8

MOV BX,-1

IMUL BX ;(DX,AX)=-8=0FFFFFFF8h:

; DX=0FFFFh,AX=0FFF8h

Итак, команды умножения выдают результат в удвоенном формате. Это не всегда удобно: изначально производилась работа с числами-байтами, а тут приходится переходить на обработку чисел-слов. В то же время далеко не всегда величина произведения столь велика, что ему нужен удвоенный формат; например, в первой и третьей из наших команд умножения для результата вполне достаточно было бы обычного формата. Поэтому важно знать, действительно ли произведению нужен двойной формат или ему достаточно и одинарного формата. Иногда об этом известно заранее (что перемножаются небольшие числа), но иногда это можно установить только после умножения. В последнем случае вопрос о том, умещается ли результат умножения в формат сомножителей или нет, решается с помощью анализа флагов переноса CF и переполнения OF, которые в обе­их командах умножения меняются синхронно и по следующему правилу:

CF=OF=1 если произведение занимает двойной формат

CF=OF=0 если произведению достаточен формат сомножителей

При CF=0 (одновременно и OF=0) можно считать, что произведение байтов за­нимает только регистр AL, а произведение слов - только регистр АХ, и дальше можно работать только с этими регистрами. Но если CF=1, то далее приходится работать с произведением как с числом удвоенного формата.

О команде умножения в процессорах 80186 и старше

Фиксированность местонахождения первого операнда и результата и невозможность указывать непосредственный операнд в командах умножения делают эти команды не очень удобными. Поэтому в процессоре 80186 была введена новая команда умножения с тремя операндами, где некоторые из этих неудобств устранены. В языке ассемблера эта команда допускает две эквивалентные формы записи:

MUL op1,op2,op3 или IMUL op1,op2,op3

и реализует следующее действие: op1:=op2*op3.

Допустимые типы операндов: op1: r16; op2: r16, m16; op3: i16.

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

X DW ?

...

MUL SI,BX,3 ;SI:=BX*3

IMUL DX,X,-10 ;DX:=X*(-10)

Данная команда умножения предназначена для умножения только чисел размером в слово и только при условии, что произведение умещается в слово. При этом условии нет разницы между умножением чисел со знаком и чисел без знака, поэтому-то в языке ассемблера и можно использовать любое из двух названий этой команды. Если указанное условие действительно выполняется, тогда флаги CF и OF получают значение 0, но если результат превосходит размер слова, тогда левые, на­иболее значимые, биты произведения теряются, в регистр op1 записываются последние 16 битов, а флаги CF и OF устанавливаются в 1.

Допускается следующее сокращение в записи рассматриваемой команды умножения: если op1=op2, т. е. если первый сомножитель берется из регистра, в который должен быть записан результат, тогда в записи команды этот регистр может быть указан только раз:

MUL op1, op3(IMUL op1, op3) сокращение для MUL op1,op1,op3

Например:

MUL DX,15 ;DX:DX*(15)

Важное замечание. По умолчанию ассемблер разрешает указывать в тексте программы на языке ассемблера только те команды, которые имеются в процессоре 8086, и фиксирует ошибку, если указаны команды, которые появились лишь в более старших моделях процессоров семейства 80x86. Так вот, чтобы ассемблер пра­вильно воспринимал новые команды, скажем, процессора 80186 (в частности, новую команду умножения в любом ее варианте), в текст программы (в любом месте, но до первой такой команды) должна быть помещена директива

.186

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

Пример. Пусть X – байтовая переменная, a Y – переменная размером в слово и надо выполнить присваивание Y:=5*X*X-7*Y при условии, что числа знаковые и все вычисления укладываются в размер слова. Тогда это можно сделать так:

.186 ;допускаются все команды процессора 80186

...

MOV AL,X

IMUL AL ;АХ:=Х*Х («обычное» умножение)

IMUL АХ,5 ;АХ:=Х*Х*5 (можно: MUL АХ,5 или IMUL

; AX, AX,5) ,AX,5)

IMUL BX,Y,-7 ;BX:=Y*(-7)

ADD AX,BX

MOV Y,AX

В данном практикуме нет необходимости выходить за рамки системы команд процессора 8086, поэтому в дальнейшем не будет использоваться рассмотренный здесь вариант команды умножения.

Команды деления

Как и умножение, деление чисел без знака и со знаком также реализуется двумя командами:

Деление целых без знака (divide): DIV op

Деление целых со знаком (integer divide): IDIV op

Первая из этих команд предназначена для деления без знаковых целых чисел, а вторая - для деления знаковых чисел, в остальном же эти команды действуют одинаково:

деление слова на байт:

АН:=АХ mod op, AL:=AX div op (op: r8, m8)

деление двойного слова на слово:

DX:=(DX,AX) mod op, AX:=(DX,AX) div op (op: r16,m16)

Как видно, в этих командах местонахождение первого операнда (делимого) и результата фиксировано и потому явно не указывается. Указывается только второй операнд (делитель), который может находиться в регистре или в ячейке памяти, но не может быть непосредственным операндом.

При делении слова на байт делимое обязано находиться в регистре АХ, а делитель должен быть байтом. При делении двойного слова на слово делимое обязано находиться в двух регистрах - в DX (старшая часть делимого) и в АХ (младшая часть), а делитель должен иметь размер слова.

В области целых чисел «настоящее» деление невозможно, и в ПК под делением понимают получение сразу двух величин - неполного частного (div) и остатка (mod). Оба этих числа помещаются на место делимого: его старшая часть заменяется на остаток, а младшая – на неполное частное. Оба этих числа имеют один и тот же размер, совпадающий с размером второго операнда (делителя).

Если через функцию trunc(x) обозначить отбрасывание дробной части вещественного числа х, тогда операции div и mod определяются следующим образом:

a div b = trunc(a/b)

a mod b = a-b*(a div b)

Примеры:

13 div 4=trunc (3.25)=3 13 mod 4=13-4*3 =1

(-13) div 4=trunc(-3.25)=-3 (-13) mod 4=(-13)-4*(-3) =-1

13 div (-4)=trunc(-3.25)=-3 13 mod (-4)=13-(-4)*(-3)=1

(-13) div (-4)*trunc(3.25)=3 (-13) mod (-4)-(-13)-(-4)*3 =-1

И, наконец, следует отметить, что при выполнении команды деления возможно появление ошибки с названием «деление на 0 или переполнение». Она возникает в двух случаях:

– делитель равен 0 (ор=0),

– неполное частное не вмещается в отведенное ему место (регистр AL или АХ); это, например, произойдет при делении 600 на 2:

MOV АХ,600

MOV ВН,2

DIV ВН ; 600 div 2 = 300, но 300 не вмещается в AL

При такой ошибке ПК прекращает выполнение программы.