любой длины. Действие начинается со сложения самых правых слов
складываемых полей. В первом цикле складываются правые cлова, во втором -
слова, расположенные левее. При этом адреса в регистрах SI, DI и BX
уменьшаются на 2. По две команда DEC выполняют эту операцию для каждого
регистра. Применять команду
SUB reg,02
в данном случае нельзя, т.к. при этом будет очищен флаг переноса, что
приведет к искажению результата сложения.
Ввиду наличия цикла, используется только одна команда сложения ADC.
Перед циклом команда CLC (CLear Carry - очистить флаг переноса)
устанавливает нулевое значение флага переноса. Для работы данного метода
необходимо: 1) обеспечить смежность слов, 2) выполнять обработку справа
налево и 3) загрузить в регистр CX число складываемых слов.
Для многословного вычитания используется команда SBB (SuBtract with
Borrow - вычитание с заемом) эквивалентная команде ADC. Заменив в
процедуре E10DWD (рис.12.2) команду ADC на SBB, получим процедуру для
вычитания.
БЕЗЗНАКОВЫЕ И ЗНАКОВЫЕ ДАННЫЕ
________________________________________________________________
Многие числовые поля не имеют знака, например, номер абонента, aдрес
памяти. Некоторые числовые поля предлагаются всегда положительные,
например, норма выплаты, день недели, значение числа ПИ. Другие числовые
поля являются знаковые, так как их содержимое может быть положительным или
отрицательным. Например, долговой баланс покупателя, который может быть
отрицательным при переплатах, или алгебраическое число.
Для беззнаковых величин все биты являются битами данных и вместо
ограничения +32767 регистр может содержать числа до +65535. Для знаковых
величин левый байт является знаковым битом. Команды ADD и SUB не делают
разницы между знаковыми и беззнаковыми величинами, они просто складывают и
вычитают биты. В следующем примере сложения двух двоичных чисел, первое
число содержит единичный левый бит. Для беззнакового числа биты
представляют положительное число 249, для знакового - отрицательное число
-7:
Беззнаковое Знаковое
11111001 249 -7
00000010 2 +2
--- --
11111011 251 -5
Двоичное представление результата сложения одинаково для беззнакового и
знакового числа. Однако, биты представляют +251 для беззнакового числа и
-5 для знакового. Таким образом, числовое содержимое поля может
интерпретироваться по разному.
Состояние "перенос" возникает в том случае, когда имеется пеpенос в
знаковый разряд. Состояние "переполнение" возникает в том случае, когда
перенос в знаковый разряд не создает переноса из разрядной сетки или
перенос из разрядной сетки происходит без переноса в знаковый разряд. При
возникновении переноса при сложении беззнаковых чисел, результат
получается неправильный:
Беззнаковое Знаковое CF OF
11111100 252 -4
00000101 5 +5
--- --
00000001 1 1 1 0
(неправильно)
При возникновении переполнения при сложении знаковых чисел, результат
получается неправильный:
Беззнаковое Знаковое CF OF
01111001 121 +121
00001011 11 +11
--- ----
10000100 132 -124 0 1
(неправильно)
При операциях сложения и вычитания может одновременно возникнуть и
переполнение, и перенос:
Беззнаковое Знаковое CF OF
11110110 246 -10
10001001 137 -119
--- ----
01111111 127 +127 1 1
(неправильно) (неправильно)
УМНОЖЕНИЕ
________________________________________________________________
Операция умножения для беззнаковых данных выполняется командой MUL, а
для знаковых - IMUL (Integer MULtiplication - умножение целых чисел).
Ответственность за контроль над форматом обрабатываемых чисел и за выбор
подходящей команды умножения лежит на самом программисте. Существуют две
основные операции умножения:
"Б а й т н а б а й т". Множимое находится в регистре AL, а
множитель в байте памяти или в однобайтовом регистре. После умножения
произведение находится в регистре AX. Операция игнорирует и стиpает любые
данные, которые находились в регистре AH.
| AH | AL | | AX |
До умножения: | |Множимое| После: |Произведение|
"С л о в о н а с л о в о". Множимое находится в регистре AX, а
множитель - в слове памяти или в регистре. После умножения произведение
находится в двойном слове, для которого требуется два регистра: старшая
(левая) часть произведения находится в регистре DX, а младшая (правая)
часть в регистре AX. Операция игнорирует и стирает любые данные, которые
находились в регистре DX.
| AX | | DX || AX |
До умножения:|Множимое| После: |Ст.часть||Мл.часть|
| Произведение |
В единственном операнде команд MUL и IMUL указывается множитель.
Рассмотрим следующую команду:
MUL MULTR
Если поле MULTR определено как байт (DB), то операция предполагает
умножение содержимого AL на значение байта из поля MULTR. Если поле MULTR
определено как слово (DW), то операция предполагает умножение содержимого
AX на значение слова из поля MULTR. Если множитель находится в регистре,
то длина регистра определяет тип операции, как это показано ниже:
MUL CL ;Байт-множитель: множимое в AL, произвед. в AX
MUL BX ;Слово-множитель:множимое в AX, произвед. в DX:AX
Беззнаковое умножение: Команда MUL
------------------------------------
Команда MUL (MULtiplication - умножение) умножает беззнаковые числа.
На рис.12.3 в процедуре C10MUL дано три примера умножения: байт на байт,
слово на слово и слово на байт. Первый пример команды MUL умножает шест.80
(128) на шест.47 (64). Произведение шест.2000 (8192) получается в регистре
AX.
__________________________________________________________________________
page 60,132
TITLE EXMULT (COM) Пример команд умножения
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
OR6 100H
BEGIN: JMP SHORT MAIN
; -------------------------------------------
BYTE1 DB 80H
BYTE2 DB 40H
WORD1 DW 8000H
WORD2 DW 4000H
; -------------------------------------------
MAIN PROC NEAR ;Основная процедура:
CALL C10MUL ;Вызвать умнож. MUL
CALL D10IMUL ;Вызвать умнож. IMUL
RET
MAIN ENDP
; Пример умножения MUL:
; --------------------
C10MUL PROC
MOV AL,BYTE1 ;Байт * байт
MUL BYTE2 ; произведение в AХ
MOV AX,WORD1 ;Слово * слово
MUL WORD2 ; произведение в DX:AX
MOV AL,BYTE1 ;Байт * слово
SUB AН,AН ; расшир. множ. в AН
MUL WORD1 ; произведение в DX:AX
RET
C10MUL ENDP
; Пример умножения IMUL:
; ---------------------
D10IMUL PROC
MOV AL,BYTE1 ;Байт * байт
IMUL BYTE2 ; произведение в AХ
MOV AX,WORD1 ;Слово * слово
IMUL WORD2 ; произвед. в DX:AX
MOV AL,BYTE1 ;Байт * слово
CBW ; расшир. множ. в AН
IMUL WORD1 ; произвед. в DX:AX
RET
D10IMUL ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.12.3. Беззнаковое и знаковое умножение.
Второй пример команды MUL генерирует шест.10000000 в регистpах DX:AX.
Третий пример команды MUL выполняет умножение слова на байт и требует
расширение байта BYTE1 до размеров слова. Так как предполагаются
беззнаковые величины, то в примере левый бит регистра AH равен нулю. (При
использовании команды CBW значение левого бита регистpа AL может быть 0
или 1). Произведение - шест.00400000 получается в регистрах DX:AX.
Знаковое умножение: Команда IMUL
----------------------------------
Команда IMUL (Integer MULtiplication - умножение целых чисел)
умножает знаковые числа. На рис.12.3 в процедуре D10IMUL используются те
же три примера умножения, что и в процедуре C10MUL, но вместо команд MUL
записаны команды IMUL.
Первый пример команды IMUL умножает шест.80 (отрицательное число) на
шест.40 (положительное число). Произведение - шест.E000 получается в
регистре AX. Используя те же данные, команда MUL дает в результате
шест.2000, так что можно видеть разницу в использовании команд MUL и IMUL.
Команда MUL рассматривает шест.80 как +128, а команда IMUL - как -128. В
результате умножения -128 на +64 получается -8192 или шест.E000.
(Попробуйте преобразовать шест.Е000 в десятичный формат).
Второй пример команды IMUL умножает шест.8000 (отрицательное
значение) на шест.2000 (положительное значение). Произведение -
шест.F0000000 получается в регистрах DX:AX и представляет собой
oтрицательное значение.
Третий пример команды IMUL перед умножением выполняет расширение
байта BYTE1 до размеров слова в регистре AX. Так как значения
предполагаются знаковые, то в примере используется команда CBW для
перевода левого знакового бита в регистр AH: шест.80 в pегистре AL
превращается в шест.FF80 в регистре AX. Поскольку множитель в слове WORD1
имеет также отрицательное значение, то произведение должно получится
положительное. В самом деле: шест.00400000 в регистрах DX:AX - такой же
результат, как и в случае умножения командой MUL, которая предполагала
положительные сомножители.
Таким образом, если множимое и множитель имеет одинаковый знаковый
бит, то команды MUL и IMUL генерируют одинаковый результат. Но, если
сомножители имеют разные знаковые биты, то команда MUL вырабатывает
положительный результат умножения, а команда IMUL - отрицательный.
Можно обнаружить это, используя отладчик DEBUG для трассировки
примеров.
П о в ы ш е н и е э ф ф е к т и в н о с т и у м н о ж е н и я: При
умножении на степень числа 2 (2,4,8 и т.д.) более эффективным является
сдвиг влево на требуемое число битов. Сдвиг более чем на 1 требует
загрузки величины сдвига в регистр CL. В следующих примерах предположим,
что множимое находится в регистре AL или AX:
Умножение на 2: SHL AL,1
Умножение на 8: MOV CL,3
SHL AX,CL
Многословное умножение
------------------------
Обычно умножение имеет два типа: "байт на байт" и "слово на слово".
Как уже было показано, максимальное знаковое значение в слове ограничено