Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Умножение и деление целых чисел




В отличие от сложения и вычитания в микропроцессоре существуют по 2 операции умножения и деления: отдельно для чисел без знака и для чисел со знаком.

Инструкции MUL используется для умножения беззнаковых величин, а инструкция IMUL – для умножения знаковых чисел. Обе инструкции могут изменять состояние флагов переноса CF и переполнения OF. На программиста возлагается задание формата данных, подлежащих обработке, и выбор подходящей инструкции умножения.

Формат инструкций следующий:

MUL регистр

MUL память

IMUL регистр

IMUL память.

Можно умножать байт на байт, слово на слово и в 32-разрядных моделях Intel – двойное слово на двойное слово.

Как видно из формата, в команде указывается только один из сомножителей, второй сомножитель по умолчанию располагается в регистре AL для байтовых операндов и в регистре АХ – для двухбайтовых операндов.

Для операции умножения правило операндов описано таблицей:

 

 

Сомножитель_1 Сомножитель_2 Результат
Байт (в РОН или ячейке памяти) AL 16 бит в АХ: в AL – младшая часть результата, в AH - старшая
Слово (в РОН или ячейке памяти) АХ 32 бита в паре DX: AX; в AX – младшая часть результата, в DX – старшая часть результата

 

Примеры команды MUL:

BYTE1 DB 80H

BYTE2 DB 40H

WORD1 DW 8000H

WORD2 DW 2000H

MOV AL,BYTE1;байт умножается на байт

MUL BYTE2;результат в АХ, равный 2000Н (8192=128*64)

(если до команды MOV AL,BYTE1 в АН содержались какие-либо данные, командой MUL BYTE2 эти данные будут затерты)

MOV AX,WORD1;слово умножается на слово

MUL WORD2;результат в в DX:AX, равный 1000 0000Н

Как видно из таблицы, операнды-сомножители должны иметь одинаковый формат: либо оба операнда – байты, либо оба операнда – слова. Если потребуется умножить байт на слово, необходимо сначала привести в соответствие размеры операндов. В Ассемблере существуют команды CBW –преобразовать байт в слово и CWD – преобразовать слово в двойное слово. Обе команды не имеют операндов. Команда CBW по умолчанию оперирует содержимым регистра AL, а результат помещает в регистр AX. Команда CWD по умолчанию выбирает слово из регистра AX и помещает результат в DX:AX. Преобразование заключается в заполнении битом знакового разряда старших регистров результата – для команды CBW – регистра АН, а для команды CWD – регистра DX.

СBW – преобразовать байт в регистре AL в слово в регистре АХ путем распространения старшего бита AL на все биты регистра AH;

CWD –преобразовать слово в регистре АХ в двойное слово в регистрах AX и DX, путем распространения старшего 15-ого бита регистра АХ на все биты регистра DX. Эти команды позволяют приводить разноформатные операнды к одному формату (большему).

Обе команды дают верный результат при работе со знаковыми данными, но могут давать ошибочные результат с беззнаковыми данными. Например,

MOV AL,BYTE2

CBW

позволит получить результат в АХ, равный 0040Н, а команды

MOV AL,BYTE1

CBW

даст результат в АХ, равный FF80H, что, конечно, неверно.

Поэтому для беззнаковых данных при необходимости преобразования к большему формату следует заполнить нулями старшую часть операнда расширенного формата и оперировать в последующих командах расширенным операндом, например:

MOV AL,BYTE1

MOV AH, 0;поместили сомножитель в регистр АХ

MUL WORD2;результат в в DX:AX, равный 1 0000Н

Команда IMUL реализует перемножение знаковых чисел. Результаты применения этой инструкции к приведенным выше данным будут следующие:

MOV AL,BYTE1;байт умножается на байт

IMUL BYTE2;результат в АХ, равный E000Н (-8192=-128*64)

MOV AX,WORD1;слово умножается на слово

IMUL WORD2;результат в в DX:AX, равный F0000000Н

MOV AL,BYTE1

CBW;поместили сомножитель в регистр АХ (FF80H)

IMUL WORD1;результат в в DX:AX, равный 0040 0000Н.

 

После выполнения команд флаги СF и OF показывают какая часть произведения существенна для дальнейших операций. При умножении чисел без знака эти флаги равны 0, если старшая часть результата нулевая, в противном случае (результат превысил по значащим цифрам сомножители) флаги устанавливаются в 1. Приумножении чисел со знаком флаги равны 0, если старшая половина произведения содержит расширение знакового разряда младшей половины (при положительном результате это 0, при отрицательном –1). Обратите внимание, что эти операции не позволяют иметь в качестве операнда константу (непосредственное значение).

Результат перемножения правильных неупакованных BCD-чисел может быть представлен в неупакованном формате BCD-чисел с помощью команды ААМ. Команда работает с регистрами AL и AH и выполняет следующее: делит значение регистра AL на 10 и запоминает частное в регистре АН (старшая неупакованная цифра результата) и остаток – регистре AL (младшая неупакованная цифра результата). Однако очевидно, что этими операциями можно выполнить только табличное умножение. Для более сложных операций умножения необходимо разработать программу, реализующую умножение “в столбик”, получение частных произведений, их сдвиги и сложение. Операции, аналогичной ААМ для упакованных BCD-чисел в микропроцессоре не существует.

Инструкции DIV используется для деления беззнаковых величин, а инструкция IDIV – для деления знаковых чисел. На программиста возлагается выбор подходящей команды деления в каждом конкретном случае..

Формат инструкций следующий:

DIV регистр

DIV память

IDIV регистр

IDIV память.

Можно делить слово на байт, двойное слово на слово и в 32-разрядных моделях Intel – учетверенное слово на двойное слово.

Правило расположения операндов в операциях деления отражается в таблице:

Делимое Делитель Частное Остаток
Слово 16 бит в регистре АХ Байт (в РОН или ячейке памяти) Байт в регистре AL Байт в регистре AH
32 бита в DX –старшая часть, в АХ- младшая Слово 16 бит (в РОН или ячейке памяти) Слово 16 бит в регистре АХ Слово 16 бит в регистре DX

 

Для деления слова на байт делимое помещают в регистр АХ, а делитель – это байт в памяти или в регистре общего назначения. Операция деления помещает частное в регистр AL, а остаток – в регистр AH (обратите внимание на то, что байтовое частное может содержать небольшие значения: для чисел без знака – до 255, а для знаковых величин - -127--+127).

Примеры:

BYTE1 DB 80H

BYTE2 DB 16H

WORD1 DW 2000H

WORD2 DW 0010H

WORD3 DW 1000H

MOV AX,WORD1

DIV BYTE1;слово делится на байт, частное – в AL, остаток– в AH

(в этом примере 8192 (2000Н) делится на 128 (80Н), частное в AL равно 64 (40Н), а остаток 0 в регистре AH)

XOR AH,AH

MOV AL,BYTE1

DIV BYTE2

(в этом примере байт преобразуется в слово и затем значение 128 (80Н) делится на 22 (16Н), в результате получается частное 05Н в регистре AL и остаток 18 (12Н) – в регистре AH.

MOV DX,WORD2

MOV AX,WORD3

DIV WORD2;двойное слово делится на слово, частное – в AХ, остаток– в DX, в этом примере частное равно 0080Н, а остаток – 1000Н)

XOR DX,DX

MOV AX,WORD1

DIV WORD3

(в этом примере слово преобразуется к формату двойного слова и делится на слово, частное от деления равное 2Н получается в регистре AХ, а остаток 0Н – в регистре DX).

Деление чисел со знаком:

MOV AX,WORD1

IDIV BYTE1;слово делится на байт, частное – в AL, остаток– в AH

(в этом примере положительное число 8192 (2000Н) делится на отрицательное число -128 (80Н), частное в AL равно -64 (С0Н), а остаток 0 в регистре AH)

MOV AL,BYTE1

CBW

IDIV BYTE2

(в этом примере байт преобразуется в слово и затем значение -128 (80Н) делится на 22 (16Н), в результате получается частное FBН (-5)в регистре AL и остаток EEН (-18)– в регистре AH.

MOV DX,WORD2

MOV AX,WORD3

IDIV WORD2;двойное слово делится на слово, частное – в AХ, остаток– в DX, в этом примере частное равно 0080Н, а остаток – 1000Н)

MOV AX,WORD1

CWD

IDIV WORD3

(в этом примере слово преобразуется к формату двойного слова и делится на слово, частное от деления равное 2Н получается в регистре AХ, а остаток 0Н – в регистре DX).

Эти примеры подтверждают тот факт, что при одинаковых знаках делимого и делителя команды деления DIV и IDIV дают одинаковые результаты, а при разных знаках делимого и делителя IDIV генерирует отрицательное значение частного и остатка.

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

1) при делении чисел без знака для ситуации первой строки таблицы делимое более чем в 256 раз больше делителя,

2) при делении чисел без знака для ситуации второй строки таблицы делимое более чем в 65636 раз больше делителя,

3) при делении чисел со знаком для ситуации первой строки таблицы делимое более чем в 128 раз больше значения делителя,

4) при делении чисел со знаком для ситуации второй строки таблицы делимое более чем в 32768 раз больше значения делителя.

Для всех вышеперечисленных ситуаций характерно то, что результат деления превышает по размеру регистр, предназначенный для его хранения.

Если частное слишком велико, можно выполнить деление с помощью последовательного вычитания делителя из делимого, например, делимое представляет слово, а делитель – байт, однако результат деления превышает байт (численные значения могут быть такими: делимое-64000, делитель – 80, результат деления 800 превышает максимальное значение, хранимое в одном байте). Фрагмент программы при условии, что делимое находится в регистре АХ, а делитель – в регистре ВХ, может быть следующим:

SUB CX,CX;очистка регистра частного

L20: CMP AX,BX;если делимое меньше делителя

JB L30;вычитания закончить

SUB AX,BX;вычесть делитель из делимого

INC CX;увеличить частное на 1

JMP L20;идти на начало цикла вычитания

L30:........

При попадании в точку L30 СХ содержит частное, АХ – остаток.

Если делимое – двойное слово в паре DX:AX, то

SUB CX,CX;очистка регистра частного

L20: CMP DX,0;пока DX не 0 – делимое больше делителя

JNE L30

CMP AX,BX;если делимое меньше делителя

JB L40;вычитания закончить

L30: SUB AX,BX;вычесть делитель из делимого

SBB DX,0;учесть возможный заем

INC CX;увеличить частное на 1

JMP L20;идти на начало цикла вычитания

L40:........

Большое делимое и малый делитель вызовут многократное повторение команд!

Если необходимо разделить число на степени числа 2, то можно деление заменить сдвигами, например требуется разделить двойное слово в паре DX:AX на 16:

SHR AX,04;делим младшую часть делимого

MOV BL,DL;сохраняем 3-ий байт в BL

SHR DX,04; делим старшую часть делимого

SHL BL,04;умножаем 3-ий байт на 16, поскольку младший полубайт старшего слова должен перейти в старший полубайт младшего слова результата

OR AH,BL добавляем полубайт к 3-ему байту результата

Для вышеприведенного фрагмента можно дать следующую наглядную интерпретацию(см. рисунок 9.1). Первая позиция рисунка отображает исходное значение двойного слова, каждая следующая позиция отражает результат выполнения команды программы. Не отражаемые в очередной позиции байты регистров не изменяются, т.е. остаются такими же, как и в предыдущей позиции. В правильности результата легко убедиться, если сдвинуть на 4 разряда вправо каждый разряд исходного кода.

 

DX AX

       
   


1 1 1 0 1 0 1 1
1 0 1 1 0 1 0 1
1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1

 
 

 


DL BL

 
 

 

 


DX

BL

                       
   
 
0 0 0 0 0 1 0 1
 
0 1 0 1 1 1 1 1
   
0 1 0 1 1 1 1 0
 
 
     
 

 

 


DX AX

 

Рисунок 9.1. Наглядная интерпретация фрагмента программы деления двойного слова на 16

 

Процесс выполнения деления 2 неупакованных BCD-чисел может быть представлен в формате неупакованных BCD-чисел. Для этого перед операцией деления в регистре АХ получают 2 неупакованные цифры делимого (выполняет эту операцию программист удобным для него способом). Далее командой AAD преобразуется число в двоичное, которое затем является делимым в операции DIV. Причем в дальнейшей операции DIV двоичное число делится на неупакованную BCD-цифру, находящуюся в байтовом регистре или в байтовой ячейке памяти. Результат операции получается так, как описано 1-ой строкой таблицы. Понятно, что с применением этих команд можно выполнять очень простые операции деления, но команду AAD можно использовать и в контексте преобразования упакованного (или неупакованного) десятичного числа из диапазона 00-99 в двоичный эквивалент.

 

 

Рассмотрев арифметические операции можно сделать следующие выводы:

1) рассмотренная нами группа команд выполняет известные арифметические операции над целыми числами, для работы с вещественными числами применяют команды сопроцессора;

2) многие команды имеют только один операнд или не имеют операндов вообще, поскольку по умолчанию работают с определенными регистрами общего назначения;

3) арифметические операции чувствительны к размерности операндов, поэтому эту характеристику необходимо отслеживать программисту;

4) контроль за правильностью арифметических операций полностью лежит на программисте; программист должен отслеживать состояние арифметических флагов во время вычислительного процесса и принимать правильные решения по дальнейшей обработке;

5) для чисел со знаком установка в 1 флага OF говорит о том, что в результате сложения чисел одного знака результат выходит за границу допустимых значений чисел со знаком в данном формате и сам результат меняет знак (имеет другой знак, чем его операнды).

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...