Вычисление выражения по формуле - Assembler (223260)
Формулировка задачи:
Необходимо посчитать след. формулу:
Вот программа, которую собрал из учебника:
title prim
assume cs:cod, ds:d, ss:s
s segment stack
dw 128 dup (?)
s ends
d segment
;резервируем области под переменные a, b, c
a dw ?
b dw ?
c dw ?
;размещаем строки – подсказки для ввода переменных
msga db ‘Введите a:$’
msgb db ‘Введите b:$’
msgc db ‘Введите c:$’
;размещаем строки – сообщения об ошибках
err1 db ‘Деление на ноль (первая дробь)$’
err2 db ‘Деление на ноль (вторая дробь)$’
;описываем данные для процедур ввода и вывода целых чисел
.
.
.
d ends
c od segment
;описываем процедуры ввода и вывода целых чисел
cr = 0dh ;cr присваиваем значение кода символа
;возврата каретки (клавиши «Enter»)
lf = 0ah ;lf присваиваем значение кода символа
;перевода строки
IntegerIn proc
start: mov ah,0ah ;функцией 0a вводим строку
;символов и размещаем ее в
;области string
lea dx,string
int 21h
xor ax,ax ;обнуляем ax, в котором
;будем формировать число
lea si,string+2 ;устанавливаем si на
;первый символ введенной
;строки
mov negflag,ax ;обнуляем флаг
;отрицательности числа
;(предполагаем, что оно
;будет неотрицательным)
cmp byte ptr [si],'-';первый символ – это
;минус?
jne m2 ;если нет – на m2
not negflag ;отмечаем, что число
;отрицательное
;(negflag не равен 0)
inc si ;продвигаем si со
;знака числа к первой
;цифре
jmp m ;прыгаем на разбор
;строки цифр
m2: cmp byte ptr [si],'+';первый символ – это
;плюс?
jne m ;если нет – на m
inc si ;продвигаем si со
;знака числа к первой
;цифре
;анализируем текущий символ
m: cmp byte ptr [si],cr ;если это cr – строка
;закончилась, выходим
;из цикла разбора
;символов
je ex1
cmp byte ptr [si],'0';если код символа
;меньше кода '0' –
;это не цифра
jb err ;прыгаем на метку err
cmp byte ptr [si],'9';если код символа
;больше кода '9' –
;это не цифра
ja err ;прыгаем на метку err
mov bx,10 ;домножаем полученное
;число на основание
;системы счисления
mul bx
sub byte ptr [si],'0';вычитаем код символа
;'0' (получаем
;очередную цифру)
add al,[si] ;добавляем цифру к
;числу
adc ah,0
inc si ;продвигаем si к
;следующему символу
jmp m ;организуем цикл
;функцией 09 выводим сообщение об ошибке
err: lea dx,errmsg
mov ah,9
int 21h
jmp start ;повторяем ввод
ex1: cmp negflag,0 ;число положительное?
je ex ;если да – выходим
neg ax ;меняем знак числа
ex: ret
IntegerIn endp
IntegerOut proc
xor cx,cx ;обнуляем счетчик цифр
mov bx,10 ;в bx помещаем делитель
cmp ax,0 ;проверяем знак числа
jge m ;если неотрицательное – на m
neg ax ;иначе – меняем знак числа
pushax ;сохраняем число перед вызовом
;функции, использующей ax
mov ah,2 ;функцией 02 выводим знак '-'
mov dl,'-'
int 21h
pop ax ;восстанавливаем число в ax
m: inc cx ;считаем количество
;получающихся цифр
xor dx,dx ;преобразуем делимое к 32
;разрядам
div bx ;получаем очередную цифру
pushdx ;сохраняем ее в стеке
or ax,ax ;проверяем есть ли еще цифры
jnz m ;если да – на метку m
;при выходе из цикла в стеке лежат цифры, в cx – их
;количество
m1: pop dx ;извлекаем цифру из стека
add dx,'0' ;преобразуем в код символа
mov ah,2 ;функцией 02 выводим на экран
int 21h
loopm1 ;повторяем cx раз
ret ;возвращаемся из процедуры
IntegerOut endp
;устанавливаем ds на сегмент данных
string db 255, 0, 255 dup (?)
errmsg db 'Недопустимый символ, можно'
db 'использовать только цифры',cr,lf,'$'
start: mov ax,d
mov ds,ax ;вводим значение переменныой a
Mov ah,09 ;выводим строку – подсказку для a
Lea dx,msga
Int 21h
Call IntegerIn ;вводим число
Mov a,ax ;помещаем его в область a
;вводим значение переменныой b
Mov ah,09 ;выводим строку – подсказку для b
Lea dx,msgb
Int 21h
Call IntegerIn ;вводим число
Mov b,ax ;помещаем его в область b
;вводим значение переменныой c
Mov ah,09 ;выводим строку – подсказку для c
Lea dx,msgc
Int 21h
Call IntegerIn ;вводим число
Mov c,ax ;помещаем его в область c
;проверяем знаменатели на равенство 0
Cmp c,0 ;проверяем первый знаменатель
Jnz m ;если не 0 – на m
Mov ah,09 ;выводим сообщение об ошибке
Lea dx,err1
Int 21h
Jmp err ;выходим
m: Mov ax,b ;считаем второй знаменатель
Add ax,c
Jnz m1 ; если не 0 – на m1
Mov ah,09 ;выводим сообщение об ошибке
Lea dx,err2
Int 21h
Jmp err ;выходим
;рассчитываем значение выражения
m1: Mov bx,ax ;помещаем второй знаменатель в bx
Mov ax,a ;считаем второй числитель
Imul ax
Mov cx,3
Imul cx
Idiv bx ;считаем значение второй дроби
Push ax ;сохраняем его в стеке
Mov ax,a ;считаем первый числитель
Add ax,b
Mov bx,c ;считаем значение первой дроби
Cwd
Idiv bx
Pop bx ;извлекаем из стека значение второй
;дроби
Sub ax,bx ;вычитаем
call IntegerOut ;выводим результат
;завершаем работу программы
mov ax,4c00h ;с кодом завершения 0 – без ошибок
int 21h
err: mov ax,4cffh ;с кодом завершения 0ffh (-1) – с ошибкой
int 21h
c od ends
end startРешение задачи: «Вычисление выражения по формуле»
textual
Листинг программы
title prim assume cs:cod, ds:d, ss:s LOCALS s segment stack dw 128 dup (?) s ends d segment ;резервируем области под переменные a, b, c a dw ? b dw ? y dw ? ;размещаем строки – подсказки для ввода переменных msga db 'Введите a:$' msgb db 'Введите b:$' ;размещаем строки – сообщения об ошибках err1 db 'Деление на ноль (первая дробь)$' err2 db 'Деление на ноль (вторая дробь)$' ;описываем данные для процедур ввода и вывода целых чисел string db 255, 0, 255 dup (?) errmsg db 'Недопустимый символ, можно' db 'использовать только цифры',cr,lf,'$' negflag dw 0 d ends cod segment ;описываем процедуры ввода и вывода целых чисел cr = 0dh ;cr присваиваем значение кода символа ;возврата каретки (клавиши «Enter») lf = 0ah ;lf присваиваем значение кода символа ;перевода строки IntegerIn proc @@start: mov ah,0ah ;функцией 0a вводим строку ;символов и размещаем ее в ;области string lea dx,string int 21h xor ax,ax ;обнуляем ax, в котором ;будем формировать число lea si,string+2 ;устанавливаем si на ;первый символ введенной ;строки mov negflag,ax ;обнуляем флаг ;отрицательности числа ;(предполагаем, что оно ;будет неотрицательным) cmp byte ptr [si],'-';первый символ – это ;минус? jne @@m2 ;если нет – на m2 not negflag ;отмечаем, что число ;отрицательное ;(negflag не равен 0) inc si ;продвигаем si со ;знака числа к первой ;цифре jmp @@m ;прыгаем на разбор ;строки цифр @@m2: cmp byte ptr [si],'+';первый символ – это ;плюс? jne @@m ;если нет – на m inc si ;продвигаем si со ;знака числа к первой ;цифре ;анализируем текущий символ @@m: cmp byte ptr [si],cr ;если это cr – строка ;закончилась, выходим ;из цикла разбора ;символов je @@ex1 cmp byte ptr [si],'0';если код символа ;меньше кода '0' – ;это не цифра jb @@err ;прыгаем на метку err cmp byte ptr [si],'9';если код символа ;больше кода '9' – ;это не цифра ja @@err ;прыгаем на метку err mov bx,10 ;домножаем полученное ;число на основание ;системы счисления mul bx sub byte ptr [si],'0';вычитаем код символа ;'0' (получаем ;очередную цифру) add al,[si] ;добавляем цифру к ;числу adc ah,0 inc si ;продвигаем si к ;следующему символу jmp @@m ;организуем цикл ;функцией 09 выводим сообщение об ошибке @@err: lea dx,errmsg mov ah,9 int 21h jmp @@start ;повторяем ввод @@ex1: cmp negflag,0 ;число положительное? je @@ex ;если да – выходим neg ax ;меняем знак числа @@ex: ret IntegerIn endp IntegerOut proc xor cx,cx ;обнуляем счетчик цифр mov bx,10 ;в bx помещаем делитель cmp ax,0 ;проверяем знак числа jge @@m ;если неотрицательное – на m neg ax ;иначе – меняем знак числа push ax ;сохраняем число перед вызовом ;функции, использующей ax mov ah,2 ;функцией 02 выводим знак '-' mov dl,'-' int 21h pop ax ;восстанавливаем число в ax @@m: inc cx ;считаем количество ;получающихся цифр xor dx,dx ;преобразуем делимое к 32 ;разрядам div bx ;получаем очередную цифру push dx ;сохраняем ее в стеке or ax,ax ;проверяем есть ли еще цифры jnz @@m ;если да – на метку m ;при выходе из цикла в стеке лежат цифры, в cx – их ;количество @@m1: pop dx ;извлекаем цифру из стека add dx,'0' ;преобразуем в код символа mov ah,2 ;функцией 02 выводим на экран int 21h loop @@m1 ;повторяем cx раз ret ;возвращаемся из процедуры IntegerOut endp ;устанавливаем ds на сегмент данных start: mov ax,d mov ds,ax ;вводим значение переменныой a Mov ah,09 ;выводим строку – подсказку для a Lea dx,msga Int 21h Call IntegerIn ;вводим число Mov a,ax ;помещаем его в область a ;вводим значение переменныой b Mov ah,09 ;выводим строку – подсказку для b Lea dx,msgb Int 21h Call IntegerIn ;вводим число Mov b,ax ;помещаем его в область b mov ax, a sub ax, b Cmp ax,0 ;проверяем первый знаменатель Jnz m ;если не 0 – на m Mov ah,09 ;выводим сообщение об ошибке Lea dx,err1 Int 21h Jmp error ;выходим m: Mov ax,a ;считаем второй знаменатель Add ax,b Jnz m1 ; если не 0 – на m1 Mov ah,09 ;выводим сообщение об ошибке Lea dx,err2 Int 21h Jmp error ;выходим ;рассчитываем значение выражения m1: Mov ax, a imul a ;ax:=a^2 Imul b Imul b Imul b ;ax:=a^2*b^3 mov bx,3 imul bx ;ax:=3*a^2*b^3 add ax, 1 ;ax:=3*a^2*b^3+1 cwd mov bx, a ;bx:=a-b sub bx, b idiv bx ;ax:=(a^2*b^3+1)/(a-b) mov cx,ax ;сохранение значения первой дроби в cx Mov ax,a sal ax,1 sal ax,1 ;ax:=a/4 add ax,b ;ax:=a/4+b mov bx,a add bx,b Idiv bx ;считаем значение второй дроби Sub cx,ax ;вычитаем mov ax,cx call IntegerOut ;выводим результат ;завершаем работу программы mov ax,4c00h ;с кодом завершения 0 – без ошибок int 21h error: mov ax,4cffh ;с кодом завершения 0ffh (-1) – с ошибкой int 21h cod ends end start
Объяснение кода листинга программы
В данном коде происходит вычисление выражения по формуле a^2*b^3+1/(a-b). Список действий:
- Ввод значений переменных a и b с помощью процедуры IntegerIn.
- Проверка значения первого знаменателя (a) на ноль. Если он равен нулю, выводится сообщение об ошибке и происходит переход на метку m.
- Вычисление второго знаменателя (b) и проверка его значения на ноль. Если он равен нулю, также выводится сообщение об ошибке и происходит переход на метку m.
- Вычисление значения выражения по формуле a^2*b^3+1/(a-b).
- Сохранение значения первой дроби (a^2*b^3+1) в переменной cx.
- Вычисление значения второй дроби (a/4+b) и вычитание ее из значения первой дроби (cx).
- Вывод результата вычисления на экран с помощью процедуры IntegerOut.
- Завершение работы программы с кодом завершения 0 (без ошибок) или 0ffh (-1) (с ошибкой), в зависимости от наличия ошибок в процессе выполнения программы.