Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Абель.docx
Скачиваний:
13
Добавлен:
26.11.2018
Размер:
569.84 Кб
Скачать

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 десятичных

JA F40 ; знаков, то ошибка

DEC CX

DEC CX

JLE F30 ;Обойти, если менее 3 знаков

MOV NODEC,02

MOV AX,01

F20:

MUL TENWD ;Вычислить фактор сдвига

LOOP F20

MOV SHIFT,AX

SHR AX,1 ;Округлить результат

MOV ADJUST,AX

F30:

MOV AX,BINHRS

MUL BINRATE ;Вычислить оплату

ADD AX,ADJUST ;Округлить оплату

ADC DX,00

CMP DX,SHIFT ;Результат слишком велик

JB F50 ; для команды DIV?

F40:

SUB AX,AX

JMP F70

F50:

CMP ADJUST,00 ;Сдвиг нее требуется?

JZ F80

DIV SHIFT ;Сдвинуть оплату

F70: SUB DX,DX ;Стереть остаток

F80: RET

F10MULT ENDP

; Преобразование в ASCII формат:

; -----------------------------

G10WAGE PROC

LEA SI,ASCWAGE+7 ;Установить дес. точку

MOV BYTE PTR[SI],'.'

ADD SI,NODEC ;Установить правую позицию

G30:

CMP BYTE PTR[SI],'.'

JNE G35 ;Обойти, если дес.поз.

DEC SI

G35:

CMP DX,00 ;Если dx:ax < 10,

JNZ G40

CMP AX,0010 ; то операция завершена

JB G50

G40:

DIV TENWD ;Остаток - ASCII-цифра

OR DL,30H

MOV [SI],DL ;Записать ASCII символ

DEC SI

SUB DX,DX ;Стереть остаток

JMP G30

G50:

OR AL,30H ;Записать последний ASCII

MOV [SI],AL ; символ

RET

G10WAGE ENDP

; Вывод величины оплаты:

; ---------------------

K10DISP PROC

MOV COL,50 ;Установить столбец

CALL Q20CURS

MOV CX,09

LEA SI,ASCWAGE

K20: ;Стереть лидирующие нули

CMP BYTE PTR[SI],30H

JNE K30 ; пробелами

MOV BYTE PTR[SI],20H

INC SI

LOOP K20

K30:

LEA DX,MESSG3 ;Вывод на экран

MOV AH,09

INT 21H

CMP ROW,20 ;Последняя строка экрана?

JAE K80

INC ROW ; нет - увеличить строку

JMP K90

K80:

MOV AX,0601H ; да --

CALL Q10SCR ; прокрутить и

MOV COL,00 ; установить курсор

CALL Q20CURS

K90: RET

K10DISP ENDP

; Преобразование ASCII-чисел

; в двоичное представление:

; --------------------------

M10ASBI PROC

MOV MULT10,0001

MOV BINVAL,00

MOV DECIND,00

SUB BX,BX

M20:

MOV AL,[SI] ;ASCII-символ

CMP AL,'.' ;Обойти, если дес.точка

JNE M40

MOV DECIND,01

JMP M90

M40:

AND AX,000FH

MUL MULT10 ;Умножить на фактор

ADD BINVAL,AX ;Сложить с дв.значением

MOV AX,MULT10 ;Вычислить следующий

MUL TENVD ; фактор x 10

MOV MULT10,AX

CMP DECIND,00 ;Десятичная точка?

JNZ M90

INC BX ; да - обойти точку

M90:

DEC SI

LOOP M20

;Конец цикла

CMP DECIND,00 ;Была дес.точка?

JZ M100 ; да --

ADD NODEC,BX ; сложить с итогом

M100: RET

M10ASBI ENDP

; Прокрутка экрана:

; ----------------

Q10SCR PROC NEAR ;AX установлен при вызове

MOV BH,30 ;Цвет (07 для ч/б)

SUB CX,CX

MOV DX,184FH

INT 10H

RET

Q10SCR ENDP

; Установка курсора:

; -----------------

Q20CURS PROC NEAR

MOV AH,02

SUB BH,BH

MOV DH,ROW

MOV DL,COL

INT 10H

RET

Q20CURS ENDP

CODESG ENDS

END BEGIN

__________________________________________________________________________

Рис.13.6. Расчет заработной платы.

О г р а н и ч е н и я. Первое ограничение в программе, приведенной на

рис.13.6, cостоит в том, что допускает не более шести десятичных знаков

после запятой. Другое ограничение - размер самой зарплаты и тот факт, что

сдвиг включает деление на число, кратное 10, a преобразование в

ASCII-формат включает деление на 10. Если значение времени или расценки

содержит больше шести десятичных знаков или зарплата превышает величину

около 655350, то программа выдает нулевой результат. На практике программа

может предусмотреть в данном случае вывод предупреждающего сообщения или

иметь подпрограммы для исключения таких ограничений.

К о н т р о л ь о ш и б о к. Программа, разработанная для

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

предупреждающие сообщения, но также проверять корректность вводимых

значений. Правильными символами при вводе числовых значений являются цифры

от 0 до 9 и символ десятичной запятой. Для любых других символов программа

должна выдать предупреждающее сообщение и вновь повторить запрос на ввод.

Полезной командой для проверки корректности вводимых символов является