Консультация № 186409
23.06.2012, 15:28
94.53 руб.
0 4 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
требуется написать программу для ТАSM для вычисления данных выражений.

Каждую функцию реализовать в виде отдельной подпрограммы, используя наиболее подходящий способ передачи аргументов.
Вычисления, которые встречаются несколько раз, оформить в виде макрокоманд.
Организовать ввод значений исходных переменных с клавиатуры и вывод результатов на экран. Обработать возможные ошибки при вводе чисел с клавиатуры.
Все числа считать вещественными, которые могут представляться в форме с фиксированной и плавающей точкой.

Когда то я уже задавал подобрый вопрос и он есть у меня в истории. Требуется написать так программу, чтобы она была весьма простой и максимально откоментированной.
В прошлой программе громоздким считать нужно таблицы для вывода степеней(окончание программы).
Буду очень рад если сможете написать все это в максимально возможные сроки.
Спасибо!

Обсуждение

Неизвестный
23.06.2012, 15:30
общий
Да кстати забыл:
Процессор Intel Core 2 Solo U3500
32 разрядная система.
Если чтото еще требуется дописать то только скажите - сделаю!
давно
Посетитель
7438
7205
24.06.2012, 04:45
общий
Что Вы понимаете под "формой с фиксированной и плавающей точкой"?
Числа, как вида 234.56, так и 2.3456e2 ?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
24.06.2012, 10:55
общий
Адресаты:
да имено такие числа
давно
Посетитель
7438
7205
25.06.2012, 02:39
общий
это ответ
Здравствуйте, Юдин Евгений Сергеевич!
Работу с вещественными числами, в любом случае, простой не назовешь...
Раз Вам не понравилось, как сделано в masm-е, я сделал по-другому
Надеюсь, что такое решение Вас устроит...
Имейте в виду, что при вводе переменных необходимо следить, чтобы выражение под корнем было >= 0
[code h=200]
.model small, stdcall
.386 ;необходимо для команды fcos

;макро для вычисления y^x
;в st должно находиться xlog[2]y
POWER MACRO
fld st ;x*log[2]y->st(1)
frndint ;округляем st до целого
fsub st(1),st ;st(1)-=st
fxch ;st(1)<->st
f2xm1 ;st=(2 в степени st) - 1
fld1 ;1->st
fadd ;st+=1
fscale ;y^x = st * (2 в степени st(1))
fstp st(1) ;чтобы убрать значение из st(1)
ENDM

;e^st
;st = z
EXP MACRO
fldl2e ;log(осн 2)e->st
fmulp ;st(1)*log(осн 2)e->st
POWER ;st=e^(st)
ENDM

;log[3](st)
LOG3 MACRO
fld1 ;1
fxch ;st(1)<->st
fyl2x ;st=1*log[2]st=log[2]y
fld1 ;1
fld c3 ;3
fyl2x ;st=1*log[2]3=log[2]3
fdiv ;st=st(1)/st=log[2]x/log[2]3=log[3]y
ENDM

;((log[3](y))^2-z)^(1/5)
CALC_YZ MACRO yoff,zoff
lea bx,y ;address y
fld dword ptr [bx] ;y->st
LOG3 ;st=log[3]y
fld st ;st=st(1)
fmulp ;st=log[3]y^2
lea bx,z ;address z
fsub dword ptr [bx] ;st=log[3]y^2-z
;возведем в степень 1/5
fld1 ;1
fdiv c5 ;1/5
fxch ;st(1)<->st
fyl2x ;st=st(1)*log[2]st
POWER ;находим (log[3](y)^2-z)^(1/5)
ENDM

.code
start:
mov ax, @data
mov ds, ax ;настроим сегментные регистры
mov es, ax ;на сегмент @data
mov ss, ax
mov sp, 0fffeh ;стек в вершине
;введем данные
x_loop:
lea si, sEnterX ;строка приглашения
call GetFloat ;вводим вещественное, результат в st
jc x_loop ;С=1 - ошибка формата! На повтор ввода!
fstp x ;сохраним в x
y_loop:
lea si, sEnterY
call GetFloat
jc y_loop
fstp y ;y
z_loop:
lea si, sEnterZ
call GetFloat
jc z_loop
fstp z ;z

call calc_a ;получаем в st расчет a
fst a ;сохраним в a и оставим в st(0)
push offset sNum ;адрес буфера для числовой строки
call float2str ;преобразовываем вещественное число из st(0)
lea si, sA ;строка пояснения 'a='
lea bx, sNum ;числовая строка
call prStr ;выводим две строки [si]+[bx]

call calc_b ;получаем в st расчет b
fst b ;сохраним в b и оставим в st(0)
push offset sNum ;адрес буфера для числовой строки
call float2str ;преобразовываем вещественное число из st(0)
lea si, sB ;строка пояснения 'b='
lea bx, sNum ;числовая строка
call prStr ;выводим две строки [si]+[bx]

lea si, sAny ;Press any key
call prsz ;выводим строку из si

mov ah, 0 ;ждем any key
int 16h

mov ax,4c00h
int 21h ;выход в ДОС

GetFloat proc ;ввод вещественного числа
call prsz ;выводим приглашение из si
lea dx, sBuf
mov ah, 0ah
int 21h ;вводим строку
lea ax, string ;адрес строки
push ax ;параметр в стек
call str2float ;преобразовываем в вещественное
ret ;число в st(0)
GetFloat endp

prsz proc ;вывод стоки ASCIIZ [si]
lodsb
cmp al, 0
je prret
int 29h
jmp prsz
prret:
ret
prsz endp

prStr proc near ;вывод двух строк ASCIIZ
call prsz ;первая [si]
mov si, bx
call prsz ;вторая [bx]
ret
prStr endp

;расчет a
;результат в st
calc_a proc
fld x ;st = x
fmul c3 ;st = 3*x
fcos ;st = cos(3x)
fld st ;st(1) = st
fmulp ;st = cos(3x)^2
fmul c008 ;st = 0.08*cos(3x)^2
fld z ;st = z
EXP ;st = e^z
fsubp st(1),st ;st = 0.08*cos(3x)^2 - e^z
CALC_YZ ;st = (log[3](y)^2 - z)^(1/5)
fld z ;st = z
fmul C7 ;st = 7z
faddp ;st = (log[3](y)^2 - z)^(1/5) + 7z
fdivp ;st = (0.08*cos(3x)^2 - e^z)/
ret ; ((log[3](y)^2 - z)^(1/5) + 7z)
calc_a endp

;расчет b
;результат в st
calc_b proc
CALC_YZ ;st = (log[3](y)^2 - z)^(1/5)
fld y ;st = y
fmul C5 ;st = 5y
fsubp ;st = (log[3](y)^2 - z)^(1/5) - 5y
fadd C00006 ;st = (log[3](y)^2 - z)^(1/5) - 5y + 0.00006
ret
calc_b endp

;-----------------------------------------
;П/п конвертации float <-> ASCII
;-----------------------------------------

;преобразование вещественного числа-строки во float
;если строка некорректна, то возвращается C=1
str2float proc uses si di, numstr:word
local numfloat:dword, c10num:word, nextnum:word, order:word

;будем накапивать число в регистре сопроцессора, начинаем с нуля
fldz
;будем умножать/делить на 10
mov c10num, 10
;порядок = 0
mov order, 0
;dl=0/1 - положительное/отрицательное число, dh=1 - знак задан
xor dx, dx
;cl=0/1 - целая/дробная часть, ch=1 - точка задана
xor cx, cx
;bl=0/1 - положительная/отрицательная степень после Е, bh=1 - степень задана
xor bx, bx
;адрес строки
mov si, numstr
sym_loop:
xor ax, ax
lodsb
cmp al, 0dh
je set_order ;строка кончилась
cmp al, 0
je set_order ;строка кончилась
cmp al, '+'
je plus_sign ;+
cmp al, '-'
je minus_sign ;-
cmp al, '.'
je point_sign ;.
cmp al, 'e'
je order_sign ;e
cmp al, 'E'
je order_sign ;E
cmp al, '0'
jb num_err ;ошибка - не цифра
cmp al, '9'
ja num_err
sub al, '0' ;'0'-'9' -> 0-9
mov nextnum, ax ;сохраним слово в памяти
mov dh, 1 ;после цифры задавать знак числа нельзя!
cmp bh, 0 ;вводим порядок?
jne num_order
;нет, вводим мантиссу
jcxz part_integer ;точки еще не было - целая часть числа
part_broken: ;дробная часть
fld numfloat ;вес цифры: 0.1, 0.001, 0.0001,...
fimul nextnum ;умножаем на цифру
faddp ;и добавляем до числа
fld numfloat ;формируем вес следующей цифры
fidiv c10num
fstp numfloat
jmp sym_loop
num_order: ;вводим порядок
mov ax, 10 ;вводим до конца строки двоичное число
mul order
add ax, nextnum
mov order, ax
jmp sym_loop

num_err: ;ошибка (любая)
fstp numfloat ;уберем из сопроцессора число
stc ;признак ошибки
jmp str2float_ret ;на общий выход (чтобы подправить стек)

part_integer: ;целая часть
fimul c10num ;умножаем на 10
fiadd nextnum ;и добавляем цифру
jmp sym_loop

plus_sign: ;+
cmp bh, 0 ;вводим порядок?
jne plus_order
;нет, вводим мантиссу
cmp dh, 0 ;проверим на повтор
jne num_err ;знак задан! Ошибка!
mov edx, 0100h ;помечаем, что знак задан и остался +
jmp sym_loop
plus_order: ;знак в порядке
cmp bh, 2 ;задан?
je num_err ;повтор! Ошибка!
mov bx, 0200h ;помечаем, что знак задан и остался +
jmp sym_loop

minus_sign: ;-
cmp bh, 0 ;вводим порядок?
jne minus_order
cmp dh, 0 ;проверим на повтор
jne num_err
mov edx, 0101h ;помечаем, что знак задан и стал -
jmp sym_loop
minus_order:
cmp bh, 2 ;задан?
je num_err
mov bx, 0201h ;помечаем, что знак задан и он -
jmp sym_loop

point_sign: ;.
cmp bh, 0
jne num_err ;точка в порядке запрещена
cmp ch, 0 ;проверим на повтор
jne num_err
mov ecx, 0101h ;помечаем, что точка задана
fld1
fidiv c10num ;1/10
fstp numfloat ;зададим вес первой дробной цифры (0.1)
jmp sym_loop

order_sign: ;символ порядка (e или E)
ftst ;проверим на 0
fstsw ax ;флаги в ax
sahf ;флаги в регистре флагов
jz num_err ;при задании порядка должна быть ненулевая мантисса
cmp bh, 0
jne num_err ;и только раз задано e(E)
mov bh, 1 ;помечаем, что задан порядок
jmp sym_loop

set_order: ;строка обработана, учтем порядок
cmp bh, 0 ;порядок есть?
je set_sign ;нет - на установку знака
mov cx, order ;порядок
jcxz set_sign ;порядок = 0 - ничего менять не надо
cmp bl, 0 ;+ или -
je positive_loop
negative_loop: ;-
fidiv c10num ;делим cx раз на 10
loop negative_loop
jmp set_sign
positive_loop: ;+
fimul c10num ;умножаем cx раз на 10
loop positive_loop
set_sign: ;учтем знак
cmp dl, 0 ;+ или -
je str2float_ok ;+ выходим
fchs ;меняем на -
str2float_ok:
clc ;все ок
str2float_ret:
ret
endp

;преобразование float из sp в строку по адресу pStr
float2str proc uses di, pStr:word
local dig:word, c10:word

mov c10, 10 ;будем делить на 10
mov di, pStr ;здесь будем формировать строку
ftst ;Проверяем число
fstsw ax ;флаги в ax
sahf ;флаги в регистре флагов
jnz float2str_notZero ;не 0
mov ax, '0' ;если 0, то рисуем 0 и выводим
stosw
jmp float2str_Ret ;на выход

float2str_notZero: ;не 0
jnc f2s_1 ;проверим знак
mov al, '-' ;для отрицательного выведем знак минус
stosb
fchs ;и меняем знак числа.

; Пояснение далее пойдёт на примере. ; ST(0) ST(1) ST(2) ST(3) ...
; Отделим целую часть от дробной. ; 73.25 ... что-то не наше
f2s_1:
fld1 ; 1 73.25 ...
fld st(1) ; 73.25 1 73.25 ...
; Остаток от деления на единицу даст дробную часть.
fprem ; 0.25 1 73.25 ...
; Если вычесть её из исходного числа, получится целая часть.
fsub st(2), st ; 0.25 1 73 ...
fxch st(2) ; 73 1 0.25 ...
; Сначала поработаем с целой частью. Считать количество цифр будем в CX.
xor cx, cx
; Поделим целую часть на десять,
f2s_2: fidiv c10 ; 7.3 1 0.25 ...
fxch st(1) ; 1 7.3 0.25 ...
fld st(1) ; 7.3 1 7.3 0.25 ...
; отделим дробную часть - очередную справа цифру целой части исходного числа,-
fprem ; 0.3 1 7.3 0.25 ...
; от частного оставим только целую часть
fsub st(2), st ; 0.3 1 7 0.25 ...
; и сохраним цифру
fimul c10 ; 3 1 7 0.25 ...
fistp dig ; 1 7 0.25 ...
; считаем цифры
inc cx
; сохраняем в стеке.
push dig
fxch st(1) ; 7 1 0.25 ...
; Так будем повторять, пока от целой части не останется ноль.
ftst
fstsw ax
sahf
jnz f2s_2
; Теперь выведем цифры целой части.
f2s_3: pop ax
; Вытаскиваем очередную цифру, переводим её в символ и выводим.
add al, 30h
stosb
; И так, пока не выведем все цифры.
loop f2s_3 ; 0 1 0.25 ...

; Итак, теперь возьмёмся за дробную часть, для начала проверив её существование.
fstp st(0) ; 1 0.25 ...
fxch st(1) ; 0.25 1 ...
ftst
fstsw ax
sahf
jz f2s_5 ;дробной части нет - выходим
; Если она всё-таки ненулевая, выведем точку и 6 знаков после точки
mov al, '.' ;рисуем точку
stosb
mov cx, 6 ;6 знаков после запятой
; Помножим дробную часть на десять
f2s_4: fimul c10 ; 2.5 1 ...
fxch st(1) ; 1 2.5 ...
fld st(1) ; 2.5 1 2.5 ...
; отделим целую часть - очередную слева цифру дробной части исходного числа,-
fprem ; 0.5 1 2.5 ...
; оставим от произведения лишь дробную часть
fsub st(2), st ; 0.5 1 2 ...
fxch st(2) ; 2 1 0.5 ...
; сохраним полученную цифру во временной ячейке
fistp dig ; 1 0.5 ...
; и сразу выведем.
mov ax, dig
add al, 30h
stosb
; Теперь, если остаток дробной части ненулевой
fxch st(1) ; 0.5 1 ...
ftst
fstsw ax
sahf
; и мы вывели менее cx цифр, продолжим
loopnz f2s_4 ; 0 1 ...
; Итак, число выведено. Осталось убрать мусор из стека.
f2s_5: fstp st(0) ; 1 ...
fstp st(0) ; ...
mov byte ptr [di], 0 ;закрываем строку
float2str_ret:
ret
endp

.data
x dd 0
y dd 0
z dd 0
a dd ?
b dd ?
;константы
c008 dd 0.08
c3 dd 3.
c0005 dd 0.005
c7 dd 7.
c5 dd 5.
c00006 dd 0.00006

sAny db 0dh,0ah,'Press any key',0
sEnterX db 0dh,0ah,'Enter x: ',0
sEnterY db 0dh,0ah,'Enter y: ',0
sEnterZ db 0dh,0ah,'Enter z: ',0
sA db 0dh,0ah,'a = ',0
sB db 0dh,0ah,'b = ',0
sBuf db 32
cnt db ?
string db 32 dup (?)
sNum db 32 dup (?)

end start[/code]
5
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа