1. Заголовок или название темы должно быть информативным 2. Все тексты программ должны помещаться в теги [CODE=asm] [/CODE] 3. Прежде чем задавать вопрос, см. "FAQ",если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно, такую задачу уже решали! 4. Не предлагайте свои решения на других языках, кроме Ассемблера. Исключение только с согласия модератора. 5. НЕ используйте форум для личного общения! Все, что не относиться к обсуждению темы - на PM! 6. Проверяйте программы перед тем, как выложить их на форум!!
Ошибка в программе вычисления интеграла, метод трапеций
пишу программу вычисления интеграла функции 1/ln x методом трапеций, для начала взял n=20 (затем буду увеличивать). Файл .exe создан, но выдает ошибку и вылетает. При просмотре в дебаггере вижу, что еще на этапе вычисления шага в регистре ST0 оказывается отрицательная величина, еще через пару шагов вылетает. В чем тут дело?
Заранее спасибо.
.486p .model small .stack 100h .data a dw 2 b dw 5 x dq 2 n dw 20 h dq ? y dq ?
.code main proc mov ax, @data mov ds, ax finit fild b fisub a fidiv n fst h ;вычисляем шаг h
fld1 fild b fyl2x fldln2 fmul fld1 fdiv fADD y fild b fdivr st(1), st ;вычисляем (ln a + ln b)/2
cycl: fadd y fst y
fild x fadd h fst x ;производим приращение х и каждый раз сохраняем ficom b je mult_ ;пока не равно b(=5),продолжаем
fld x fyl2x fldln2 fmul fld1 fdiv ; loop cycl ;
mult_: fld y ; fld h ; fmul ;когда х достиг значения 5, перемножаем на h
exit: mov ax, 4c00h ; int 21h ; main endp end main
IUnknown, опять вынужден обратиться. Та же многострадальная программа, но для другой функции: требуется вычислить интеграл от функции sin (3x+3) / 7x+6. Беда в том, что я привязан к средствам процессора 286 и команду fsin использовать не могу. Иду окольным путем, через процедуру вычисления частичного тангенса fptan. Пока возникли две проблемы: 1. Решительно не хочет правильно разделить pi на 4. Это переменная four в формате слова. Эксперименты с присвоением ей другого формата (dq) или обозначения (например, 4.0. вместо 4) дают еще более неправильный результат. 2. После завершения энтой процедуры вычисления синуса возврат идет не к месту ее вызова, а к началу кода.
Что за напасть?
.286p .model small .stack 100h .data mes db 'Operands not comparable', 13, 10, '$' a dw 1 b dw 5 x dd 1 n dw 0 d dw 20 eps dd 0.0001 two dw 2 three dw 3 seven dw 7 six dw 6 h dq ? y dq ? z dq ? NL db 0Dh, 0Ah, "$" STATUS DW ? FOUR dw 4 C3 EQU 40H C2 EQU 04H C1 EQU 02H C0 EQU 01H
.code
CalcF macro; На вершине стека д.б. "x"
fimul three fiadd three call sin
fstp y fld x fimul seven fiadd six fld y fdivr
endm
iCalcF macro param
fild param fimul three fiadd three
call sin fstp y fild param fimul seven fiadd six fld y fdivr
endm
Сalc_h macro mov cx, n add cx, d mov n, cx dec cx
; вычисляем шаг finit fild b fisub a fidiv n fst h ; Сохраняем шаг endm
main proc
mov ax, @data mov ds, ax
outer_: fld y fstp z Сalc_h iCalcF b fstp y iCalcF a fadd y ; Складываем fidiv two ; Делим сумму на 2 fstp y ; Сохр. начальное приближение
; внутренний цикл - вычисляем ФУНКЦИЮ fld x ; X в стек сопроцессора inner_loop: fadd h ; X <- X + h CalcF fadd y fstp y ; Сохраняем новое значение loop inner_loop
fld y fmul h fst y
call outfloat call OutInt ;выводим актуальное n finit
fld y fsub z fabs fcomp eps fstsw ax sahf
jp m2 jz m1 jc exit jmp outer_
m1: jmp outer_
m2: MOV DX, offset mes mov Ah,09 int 21h
exit: mov ax, 4c00h ; int 21h ; main endp
outfloat proc near ;вывод числа push ax push cx push dx
push bp mov bp, sp push 10 push 0 ; Проверяем число на знак, и если оно отрицательное, ftst fstsw ax sahf jnc @of1 ; то выводим минус mov ah, 02h mov dl, '-' int 21h ; и оставляем модуль числа. fchs
@of1: fld1 fld st(1) fprem fsub st(2), st fxch st(2)
xor cx, cx
@of2: fidiv word ptr [bp - 2] fxch st(1) fld st(1) fprem fsub st(2), st fimul word ptr [bp - 2] fistp word ptr [bp - 4] inc cx push word ptr [bp - 4] fxch st(1) ftst fstsw ax sahf jnz short @of2 ; Теперь выведем её. mov ah, 02h @of3: pop dx add dl, 30h int 21h ; И так, пока не выведем все цифры. loop @of3 ; Теперь за дробную часть, для начала проверив её существование. fstp st(0) fxch st(1) ftst fstsw ax sahf jz short @of5 ; Если она ненулевая, выведем точку mov ah, 02h mov dl, '.' int 21h ; и не более четырех цифр дробной части. mov cx, 4 ; Помножим дробную часть на десять, @of4: fimul word ptr [bp - 2] fxch st(1) fld st(1) ; отделим целую часть fprem ; оставим от произведения лишь дробную
часть, fsub st(2), st fxch st(2) ; сохраним полученную цифру во временной ячейке fistp word ptr [bp - 4] ; и сразу выведем. mov ah, 02h mov dl, [bp - 4] add dl, 30h int 21h ; Теперь, если остаток дробной части ненулевой fxch st(1) ftst fstsw ax sahf ; и мы вывели менее четырех цифр, продолжим. loopnz @of4 ; Осталось убрать мусор из стэка. @of5: fstp st(0) fstp st(0)
leave
mov AH,9 mov dx, offset NL int 21h
pop dx pop cx pop ax ret outfloat endp
OutInt proc near push cx push dx push bx push ax
mov ax,n xor cx, cx mov bx, 10 l1: xor dx,dx div bx push dx inc cx test ax, ax jnz l1 mov ah, 02h l2: pop dx add dl, 30h int 21h loop l2
mov AH,9 mov dx, offset NL int 21h
pop ax pop bx pop dx pop cx ret outint endp
SIN PROC near PUSH DS SUB AX, AX PUSH AX MOV AX, CS MOV DS, AX MOV ES, AX
DO_AGAIN:
FLDPI ; PI ; X FIDIV FOUR ; PI/4 ; X FXCH ; X ; PI/4 FPREM ; R ; PI/4 FSTSW STATUS FWAIT MOV AH, BYTE PTR STATUS+1 TEST AH, C1 ; Определяется, необходимо ли вычитание PI/4 JZ DO_R ; Если 0, то не нужно FSUBRP ST(1), ST(0) ; A = PI/4-R ; ? JMP SHORT DO_FPTAN
DO_R: FXCH ; PI/4 ; R FCOMP ; R ; ?
DO_FPTAN:
FPTAN ; OPP ; ADJ Где
OPP/ADJ=Tan(A)
;----- Определение того, что нужно - синус или косинус
TEST AH, C3 or C1
JPE DO_SINE
FXCH ; ADJ ; OPP DO_SINE: ; D ; N
; Вычисление N/SQR(N**2 + D**2) FMUL ST(0),ST(0) ; D**2 ; N FXCH ST(1) ; N ; D**2 FLD ST(0) ; N ; N ; D**2 FMUL ST(0),ST(0) ; N**2 ; N ; D**2 FADD ST(0), ST(2) ; N**2 + D**2 ; N ; D**2 FSQRT ; SQR(N2 + D2) ; N ; D**2 FDIVRP ST(1) ; SIN(X) ; D**2 FXCH ST(1) ; D**2 ; SIN(X) FCOMP ; SIN(X) ; ? Test ah, C0 jz return_inst fchs return_inst: RET