множители 1,10,100 и т.д. Такой прием применен для большей ясности,
однако, для большей производительности множитель можно хранить в регистре
SI или DI.
__________________________________________________________________________
TITLE EXCONV (СОМ) Преобр. ASCII и дв. ф-тов
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
; -------------------------------------------
ASCVAL DB '1234' ;Элементы данных
BINVAL DB 0
ASCLEN DB 4
MULT10 DB 1
; -------------------------------------------
MAIN PROC NEAR ;Основная процедура:
CALL B10ASBI ;Вызвать преобразование ASCII
CALL C10BIAS ;Вызвать преобразование двоичное
RET
MAIN ENDP
; -------------------------------
; Преобразование ASCII в двоичное:
; -------------------------------
B10ASBI PROC
MОV CX,10 ;Фактор умножения
LEA SI,ASCVAL-1 ;Адрес ASCVAL
MOV BX,ASCLEN ;Длина ASCVAL
В20:
MOV AL,[SI+BX] ;Выбрать ASCII-символ
AND AX,000FH ;Очистить зону тройки
MUL MULT10 ;Умножить на фактор 10
ADD BINVAL,AX ;Прибавить к двоичному
MOV AX,MULT10 ;Вычислить следующий
MUL CX ; фактор умножения
MOV MULT10,AX
DEC BX ;Последн. ASCII-символ?
JNZ В20 ; Нет - продолжить
RET
B10ASBI ENDP
; -------------------
; Преобр. дв. в ASCII:
; -------------------
C10BIAS PROC
MOV CX,0010 ;Фактор деления
LEA SI,ASCVAL+3 ;Адрес ASCVAL
MOV AX,BINVAL ;Загрузить дв. число
С20:
CMP AХ,0010 ;Значение меньше 10?
JB С30 ; Да - выйти
XOR DX,DX ;Очистить часть частного
DIV CX ;Разделить на 10
OR DL,30H
MOV [SI],DL ;Записать ASCII-символ
OEC SI
JMP С20
C30:
OR AL,30H ;3аписать поcл. частное
MOV [SI],AL ; как ASCII-символ
RET
C10BIAS ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.13.5. Преобразование ASCII и двоичного форматов.
ПРЕОБРАЗОВАНИЕ ДВОИЧНОГО ФОРМАТА В ASCII-ФОРМАТ
________________________________________________________________
Для того, чтобы напечатать или отобразить на экране арифметический
pезультат, необходимо преобразовать его в ASCII-формат. Данная операция
включает в себя процесс обратный предыдущему. Вместо умножения
используется деление двоичного числа на 10 (шест.0A) пока результат не
будет меньше 10. Остатки, которые лежат в границах от 0 до 9, образуют
число в ASCII-формате. В качестве примера рассмотрим преобразование
шест.4D2 обратно в десятичный формат:
Частное Остаток
4D2 : A 7B 4
7B : A C 3
C : A 1 2
Так как последнее частное 1 меньше, чем шест.A, то операция завершена.
Остатки вместе с последним частным образуют результат в ASCII-формате,
записываемый справа налево 1234. Все остатки и последнее частное должны
записываться в память с тройками, т.е. 31323334.
На рис.13.5 процедура C10BIAS преобразует шест.4D2 (результат
вычисления в процедуре B10ASBI) в ASCII-число 1234. Полезно переписать всю
программу (рис.13.5) в компьютер и выполнить трассиpовку ее выполнения по
шагам.
СДВИГ И ОКРУГЛЕНИЕ
________________________________________________________________
Рассмотрим процесс округления числа до двух десятичных знаков после
запятой. Если число равно 12,345, то необходимо прибавить 5 к
отбрасываемому разряду и сдвинуть число вправо на один десятичный разряд:
Число: 12,345
Плюс 5: +5
------
Округленное число: 12,350 = 12,35
Если округляемое число равно 12,3455, то необходимо прибавить 50 и
сдвинуть на два десятичных разряда. Для 12,34555 необходимо прибавить 500
и сдвинуть на три десятичных разряда:
12,3455 12,34555
+50 +500
------- --------
12,3505 = 12,35 12,35055 = 12,35
К числу, имеющему шесть знаков после запятой, необходимо прибавить 5000 и
сдвинуть на четыре десятичных разряда и т.д. Поскольку данные
представляются в компьютере в двоичном виде, то 12345 выглядит как
шест.3039. Прибавляя 5 к 3039, получим 303E, что соответствует числу 12350
в десятичном представлении. Пока все хорошо. Но вот сдвиг на одну двоичную
цифру дает в результате шест.181F, или 1675 - т.е. сдвиг на одну двоичную
цифру просто делит число пополам. Но нам необходим такой сдвиг, который
эквивалентен сдвигу вправо на одну десятичную цифру. Такой сдвиг можно
осуществить делением на 10 (шест.A):
Шест.303E : Шест.A = 4D3 или дес.1235
Преобразование шест.4D3 в ASCII-формат дает число 1235. Теперь oстается
лишь вставить запятую в правильную позицию числа 12,35, и можно выдать на
экран округленное и сдвинутое значение.
Таким образом можно округлять и сдвигать любые двоичные числа. Для
трех знаков после запятой необходимо прибавить 5 и разделить на 10, для
четырех знаков после запятой: прибавить 50 и pазделить на 100. Возможно вы
заметили модель: фактор округления (5, 50, 500 и т.д.) всегда составляет
половину фактора сдвига (10, 100, 1000 и т.д.).
Конечно, десятичная запятая в двоичном числе только подpазумевается.
ПРОГРАММА: ПРЕОБРАЗОВАНИЕ ВРЕМЕНИ И РАСЦЕНКИ РАБОТ ДЛЯ РАСЧЕТА ЗАРПЛАТЫ
_______________________________________________________________________
Программа, приведенная на рис.13.6, позволяет вводить с клавиатуры
значения продолжительности и расценки работ и отображать на экран
pасчитанную величину заработанной платы. Для краткости в программе опущены
некоторые проверки на ошибку. Программа содержит следующие процедуры:
B10INPT Вводит значения времени работы на ее расценку с клавиатуры. Эти
значения могут содержать десятичную запятую.
D10HOUR Выполняет преобразование значения времени из ASCII в двоичный
формат.
E10RATE Выполняет преобразование значения расценки из ASCII в двоичный
формат.
F10MULT Выполняет умножение, округление и сдвиг. Величина зарплаты без
дробной части или с одним или двумя знаками после запятой не
требует округления и сдвига. Данная процедура ограничена тем,
что позволяет обрабатывать величину зарплаты с точностью до
шести десятичных знаков, что, конечно, больше, чем требуется.
G10WAGE Вставляет десятичную запятую, определяет правую позицию для
начала записи ASCII символов и преобразует двоичное значение
зарплаты в ASCII-формат.
K10DISP Заменяет лидирующие нули на пробелы и выводит результат на экран
M10ASBI Преобразует ASCII в двоичный формат (общая процедура для времени
и расценки) и определяет число цифр после запятой в введенном
значении.
__________________________________________________________________________
TITLE SCREMP (EXE) Ввод времени и расценки,
;вывод величины оплаты
; ----------------------------------------------------
STACKSG SEGMENT PARA STACK 'Stack'
DW 32 DUP(?)
STACKSG ENDS
; ----------------------------------------------------
DATASG SEGMENT PARA 'Data'
HRSPAR LABLE BYTE ;Список параметров для
; ввода времени:
MAXHLEN DB 6 ;---------------------
ACTHLEN DB ?
HRSFLD DB 6 DUP(?)
RATEPAR LABLE BYTE ;Список параметров для
; ввода расценки:
MAXRLEN DB 6 ;---------------------
ACTRLEN DB ?
RATEFLN DB 6 DUP(?)
MESSG1 DB 'Hours worked? ','$'
MESSG2 DB 'Rate of pay? ','$'
MESSG3 DB 'Wage = '
ASCWAGE DB 10 DUP(30H), 13, 10, '$'
ADJUST DW ?
ASCHRS DB 0
ASCRATE DB 0
BINVAL DW 00
BINHRS DW 00
BINRATE DW 00
COL DB 00
DECIND DB 00
MULT10 DW 01
NODEC DW 00
ROW DB 00
SHIFT DW ?
TENWD DW 10
DATASG ENDS
; ----------------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATASG
MOV DS,AX
MOV ES,AX
MOV AX,0600H
CALL Q10SCR ;Очистить экран
CALL Q20CURS ;Установить курсор
A20LOOP:
CALL B10INPT ;Ввести время и расценку
CMP ACTHLEN,00 ;Завершить работу?
JE A30
CALL D10HOUR ;Получить двоичное время
CALL E10RATE ;Получить двоичную расценку
CALL F10MULT ;Расчитать оплату
CALL G10WAGE ;Преобразовать в ASCII
CALL K10DISP ;Выдать результат на экран
JMP A20LOOP
A30:
MOV AX,0600H
CALL Q10SCR ;Очистить экран
RET ;Выйти из программы
BEGIN ENDP
; Ввод времени и расценки
; ----------------------------------------------------
B10INPT PROC
LEA DX,MESSG1 ;Запрос для ввода времени
MOV AH,09
INT 21H
LEA DX,HRSPAR ;Ввести время
MOV AH,0AH
INT 21H
CMP ACTHLEN,00 ;Пустой ввод?
JNE B20
RET ; да - вернуться A20LOOP
B20:
MOV COL,25 ;Установить столбец
CALL Q20CURS
LEA DX,MESSG2 ;Запрос для ввода расценки
MOV AH,09
INT 21H
LEA DX,RATEPAR ;Ввести расценку
MOV AH,0AH
INT 21H
RET
B10INPT ENDP
; Обработка времени:
; -----------------
D10HOUR PROC
MOV NODEC,00
MOV CL,ACTHLEN
SUB CH,CH
LEA SI,HRSFLD-1 ;Установить правую позицию
ADD SI,CX ; времени
CALL M10ASBI ;Преобразовать в двоичное
MOV AX,BINVAL
MOV BINHRS,AX
RET
D10HOUR ENDP
; Обработка расценки:
; ------------------
E10RATE PROC
MOV CL,ACTRLEN
SUB CH,CH
LEA SI,RATEFLD-1 ;Установить правую позицию
ADD SI.CX ; расценки
CALL M10ASBI ;Преобразовать в двоичное
MOV AX,BINVAL
MOV BINRATE,AX
RET
E10RATE ENDP
; Умножение, округление и сдвиг:
; -----------------------------
F10MULT PROC
MOV CX,05
LEA DI,ASCWAGE ;Установить формат оплаты
MOV AX,3030H ; в код ASCII (30)
CLD
REP STOSW
MOV SHIFT,10
MOV ADJUST,00
MOV CX,NODEC
CMP CL,06 ;Если более 6 десятичных