AND AL,0FH ;Преобразовать AL в 05 0005
MUL CL ;Умножить AL на CL 002D
AAM ;Преобразовать в распак.дес. 0405
OR AX,3030H ;Преобразовать в ASCII-ф-т 3435
Команда MUL генерирует 45 (шест.002D) в регистре AX, после чего команда
AAM делит это значение на 10, записывая частное 04 в регистр AH и остаток
05 в регистр AL. Команда OR преобpазует затем распакованное десятичное
число в ASCII-формат.
Пример на рис.13.2 демонстрирует умножение четырехбайтового множимого
на однобайтовый множитель. Так как команда AAM может иметь дело только с
однобайтовыми числами, то в программе организован цикл, который
обрабатывает байты справа налево. Окончательный результат умножения в
данном примере - 0108090105.
Если множитель больше одного байта, то необходимо обеспечить еще один
цикл, который обрабатывает множитель. В этом случае проще будет
преобразовать число из ASCII-формата в двоичный формат (см. следующий
раздел "Преобразование ASCII-формата в двоичный формат").
__________________________________________________________________________
TITLE ASCMUL (COM) Умножение ASCII-чисел
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP MAIN
; ---------------------------------------------
MULTCND DB '3783' ;Элементы данных
MULTPLR DB '5'
PRODUCT DB 5 DUP(0)
; ---------------------------------------------
MAIN PROC NEAR
MOV CX,04 ;4 цикла
LEA SI,MULTCND+3
LEA DI,PRODUCT+4
AND MULTPLR,0FH ;Удалить ASCII-тройку
A20:
MOV AL,[SI] ;Загрузить ASCII-символ
; (можно LODSB)
AND AL,OFH ;Удалить ASCII-тройку
MUL MULTPLR ;Умножить
AAM ;Коррекция для ASCII
ADD AL,[DI] ;Сложить с
AAA ; записанным
MOV [DI],AL ; произведением
DEC DI
MOV [DI],AH ;Записать перенос
DEC SI
LOOP A20 ;Циклиться 4 раза
RET
MAIN ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.13.2. Умножение в ASCII-формате.
Деление в ASCII-формате
-------------------------
Команда AAD (ASCII Adjust for Division - коррекция для деления
ASCII-кодов) выполняет корректировку ASCII-кода делимого до
непосредственного деления. Однако, прежде необходимо очистить левые тройки
ASCII-кодов для получения распакованного десятичного формата. Команда AAD
может оперировать с двухбайтовыми делимыми в регистре AX. Предположим, что
регистр AX содержит делимое 3238 в ASCII-формате и регистр CL содержит
делитель 37 также в ASCII-формате. Следующие команды выполняют коррекцию
для последующего деления:
AX:
AND CL,0FH ;Преобразовать CL в распак.дес.
AND AX,0F0FH ;Преобразовать AX в распак.дес. 0208
AAD ;Преобразовать в двоичный 001C
DIV CL ;Разделить на 7 0004
Команда AAD умножает содержимое AH на 10 (шест.0A), прибавляет pезультат
20 (шест.14) к регистру AL и очищает регистр AH. Значение 001C есть шест.
представление десятичного числа 28. Делитель может быть только
однобайтовый от 01 до 09.
Пример на рис.13.3 выполняет деление четырехбайтового делимого на
однобайтовый делитель. В программе организован цикл обработки делимого
справа налево. Остатки от деления находятся в регистре AH и команда AAD
корректирует их в регистре AL. Окончательный pезультат: частное 00090204 и
в регистре AH остаток 02.
Если делитель больше одного байта, то необходимо построить другой
цикл для обработки делителя, но лучше воспользоваться следующим разделом
"Преобразование ASCII-формата в двоичный формат."
__________________________________________________________________________
TITLE ASCDIV (COM) Деление ASCII-чисел
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
; ---------------------------------------------
DIVDND DB '3698' ;Элементы данных
DIVSOR DB '4'
QUOTNT DB 4 DUP(0)
; ---------------------------------------------
MAIN PROC NEAR
MOV CX,04 ;4 цикла
SUB AH,AH ;Стереть левый байт делимого
AND DIVSOR,0FH ;Стереть ASCII 3 в делителе
LEA SI,DIVDND
LEA DI,QUOTNT
A20:
MOV AL,[SI] ;Загрузить ASCII байт
; (можно LODSB)
AND AL,0FH ;Стереть ASCII тройку
AAD ;Коррекция для деления
DIV DIVSOR ;Деление
MOV [DI],AL ;Сохранить частное
INC SI
INC DI
LOOP A20 ;Циклиться 4 раза
RET
MAIN ENDP
CODEGS ENDS
END BEGIN
__________________________________________________________________________
Рис.13.3. Деление в ASCII-формате.
ДВОИЧНО-ДЕСЯТИЧНЫЙ ФОРМАТ (BCD)
________________________________________________________________
В предыдущем примере деления в ASCII-формате было получено частное
00090204. Если сжать это значение, сохраняя только правые цифры каждого
байта, то получим 0924. Такой формат называется двоично-десятичным (BCD -
Binary Coded Decimal) (или упакованным). Он содержит только десятичные
цифры от 0 до 9. Длина двоично-десятичного представления в два раза меньше
ASCII-представления.
Заметим, однако, что десятичное число 0924 имеет основание 10 и,
будучи преобразованным в основание 16 (т.е. в шест. представление), даст
шест.039C.
Можно выполнять сложение и вычитание чисел в двоично-десятичном
представлении (BCD-формате). Для этих целей имеются две корректиpующих
команды:
DAA (Decimal Adjustment for Addition - десятичная коррекция для сложения)
DAS (Decimal Adjustment for Subtraction - десятичн. коррекция для вычит.)
Обработка полей также осуществляется по одному байту за одно
выполнение. В примере программы, приведенном на рис.13.4, выполняется
преобразование чисел из ASCII-формата в BCD-формат и сложение их.
Процедура B10CONV преобразует ASCII в BCD. Обработка чисел может
выполняться как справа налево, так и слева направо. Кроме того, обработка
слов проще, чем обработка байтов, так как для генерации одного байта
BCD-кода требуется два байта ASCII-кода. Ориентация на обработку слов
требует четного количества байтов в ASCII-поле.
Процедура C10ADD выполняет сложение чисел в BCD-формате.
Окончательный результат - 127263.
__________________________________________________________________________
TITLE BCDADD (СОМ) Преобр.ASCII в BCD, сложение
CODESG SEGMENT PARA "Code"
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
; -------------------------------------------
ASC1 DB '057836'
ASC2 DB '069427'
BCD1 DB '000'
BCD2 DB '000'
BCD3 DB 4 DUP(0)
; -------------------------------------------
MAIN PROC NEAR
LEA SI,ASC1+4 ;Инициализировать для ASC1
LEA DI,BCD1+2
CALL B10CONV ;Вызвать преобразование
LEA SI,ASC2+4 ;Инициализировать для ASC2
LEA DI,BCD2+2
CALL B10CONV ;Вызвать преобразование
CALL C10ADD ;Вызвать сложение
RET
MAIN ENDP
; Преобразование ASCII в BCD:
; --------------------------
B10CONV PROC
MOV CL,04 ;Фактор сдвига
MOV OX,03 ;Число слов В20:
MOV AX,[SI] ;Получить ASCII-пapy
(можно использовать LODSW)
XCHG AH,AL
SHL AL,CL ;Удалить тройки
SHL AX,CL ; ASCII-кода
MOV [DI],AH ;Записать BCD-цифру
DEC SI
DEC SI
DEC DI
DEC DX
JNZ В20
RET
B10CONV ENDP
; Сложение BCD-чисел:
; ------------------
C10ADD PROC
XOR AН,AН ;0чистить AН
LEA SI,BCD1+2 ;Инициализация
LEA DI,BCD2+2 ; BCD
LEA BX,BCD3+3 ; адресов
MOV CX,03 ;Трехбайтные поля
CLC
С20:
MOV AL,[SI] ;Получить BCD1 (или LODSB)
ADC AL,[DI] ;Прибавить BCD2
DAA ;Десятичная коррекция
MOV [BX],AL ;3аписать в BCD3
DEC SI
DEC DI
DEC BX
LOOP С20 ;Цикл 3 раза
RET
C10ADD ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.13.4. BCD-преобразование и арифметика.
ПРЕОБРАЗОВАНИЕ ASCII-ФОРМАТА В ДВОИЧНЫЙ ФОРМАТ
________________________________________________________________
Выполнение арифметических операций над числами в ASCII или BCD
форматах удобно лишь для коротких полей. В большинстве случаев для
арифметических операций используется преобразование в двоичный формат.
Практически проще преобразование из ASCII-формата непосредственно в
двоичный формат, чем преобразование из ASCII- в BCD-формат и, затем, в
двоичный формат:
Метод преобразования базируется на том, что ASCII-формат имеет
основание 10, а компьютер выполняет арифметические операции только над
числами с основанием 2. Процедура преобразования заключается в следующем:
1. Начинают с самого правого байта числа в ASCII-формате и
обрабатывают справа налево.
2. Удаляют тройки из левых шест.цифр каждого ASCII-байта.
3. Умножают ASCII-цифры на 1, 10, 100 (шест.1, A, 64) и т.д. и
складывают результаты.
Для примера рассмотрим преобразование числа 1234 из ASCII-формата в
двоичный формат:
Десятичное Шестнадцатиричное
4 х 1 = 4 4
3 х 10 = 30 1E
2 х 100 = 200 C8
1 х 1000 = 1000 3E8
Результат: 04D2
Проверьте, что шест.04D2 действительно соответствует десятичному
1234. На рис.13.5 в процедуре B10ASBI выполняется преобразование
ASCII-числа 1234 в двоичный формат. В примере предполагается, что длина
ASCII-числа равна 4 и она записана в поле ASCLEN. Для инициализации адрес
ASCII-поля ASCVAL-1 заносится в регистр SI, а длина - в регистр BX.
Команда по метке B20 пересылает ASCII-байт в регистр AL:
MOV AL,[SI+BX]
Здесь используется адрес ASCVAL-1 плюс содержимое регистра BX (4),
т.е. получается адрес ASCVAL+3 (самый правый байт поля ASCVAL). В каждом
цикле содержимое регистра BX уменьшается на 1, что приводит к обращению к
следующему слева байту. Для данной адресации можно использовать регистр
BX, но не CX, и, следовательно, нельзя применять команду LOOP. В каждом
цикле происходит также умножение поля MULT10 на 10, что дает в результате