IPB
ЛогинПароль:

> ПРАВИЛА РАЗДЕЛА!!!

1. Заголовок или название темы должно быть информативным
2. Все тексты программ должны помещаться в теги [CODE=asm] [/CODE]
3. Прежде чем задавать вопрос, см. "FAQ",если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно, такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Ассемблера. Исключение только с согласия модератора.
5. НЕ используйте форум для личного общения! Все, что не относиться к обсуждению темы - на PM!
6. Проверяйте программы перед тем, как выложить их на форум!!

2 страниц V  1 2 >  
 Ответить  Открыть новую тему 
> Ошибка в программе вычисления интеграла, метод трапеций
Hey
сообщение 7.09.2012 20:32
Сообщение #1


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Приветствую,

пишу программу вычисления интеграла функции 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

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 8.09.2012 12:00
Сообщение #2


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


А ты в дебаггере посмотрел, что именно грузится в ST0 при выполнении
finit
fild b ; <--- вот этой строки
fisub a
fidiv n
fst h ;вычисляем шаг h
? Там явно не 5-ка, а 8397:
Прикрепленное изображение

Измени режим процессора на .286p, тогда значения станут подгружаться нормально, и по крайней мере h вычисляется правильно, дальше не проверял.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 9.09.2012 12:30
Сообщение #3


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Спасибо, с тем фрагментом действительно пошло. Где-то дальше еще есть ошибки, сейчас буду смотреть.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 9.09.2012 14:31
Сообщение #4


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


А почему всё-таки fild пятёрки загрузил 8397?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 9.09.2012 17:30
Сообщение #5


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Снова загвоздка: не принимает директиву loop, попросту ее пропускает. Это свойство моей версии ассемблера или режима 286р?

P.S. Виноват: забыл на счетчик СХ поставить. Правда, он почему-то считает только два цикла, затем обнуляется. Притом во втором цикле в x грузит сразу 4,8 вместо 2,15. ... прилагаю новый листинг.



.286p
.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
mov CX, [n]
dec CX
finit
fild b
fisub a
fidiv n
fst h ;вычисляем шаг h

finit
fld1
fild b
fyl2x
fldln2
fmul ; вычиcляем ln 5
fld1
fdivr ;вычиcляем 1/ln 5
fstp y

fldln2
fld1
fdivr ; вычисляем 1/ln2
fadd y
fstp y
fild a
fld y
fdivr ;вычисляем (1/ln a + 1/ln b)/2
fstp y

cycl:
finit
fld x
fadd h
fst x ;производим приращение х и каждый раз сохраняем
fld1
fld x
fyl2x
fldln2
fmul
fld1 ;
fdivr ;
fadd y
fstp y
loop cycl ;

mult_:
fld y
fld h
fmul ;когда х достиг значения 5, перемножаем на h



Сообщение отредактировано: Hey - 9.09.2012 18:29
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 9.09.2012 18:14
Сообщение #6


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Цитата
Это свойство моей версии ассемблера или режима 286р?
Это особенности цикла LOOP. Чтобы он работал, надо занести число повторений в CX. У тебя CX - нулевой. Похоже, тебе нужен не LOOP, а простой JMP, если ты из цикла уходишь по "je mult_"

Цитата
А почему всё-таки fild пятёрки загрузил 8397?
А кто его знает... В 286-ом режиме грузит нормально, выше - начинает придумывать что-то своё.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 9.09.2012 18:31
Сообщение #7


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


P.S. ТОчно, забыл на счетчик СХ поставить. Правда, он почему-то считает только два цикла, затем обнуляется. Притом во втором цикле в x грузит сразу 4,8 вместо 2,15. ... прилагаю новый листинг.



.286p
.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
mov CX, [n]
dec CX
finit
fild b
fisub a
fidiv n
fst h ;вычисляем шаг h

finit
fld1
fild b
fyl2x
fldln2
fmul ; вычиcляем ln 5
fld1
fdivr ;вычиcляем 1/ln 5
fstp y

fldln2
fld1
fdivr ; вычисляем 1/ln2
fadd y
fstp y
fild a
fld y
fdivr ;вычисляем (1/ln a + 1/ln b)/2
fstp y

cycl:
finit
fld x
fadd h
fst x ;производим приращение х и каждый раз сохраняем
fld1
fld x
fyl2x
fldln2
fmul
fld1 ;
fdivr ;
fadd y
fstp y
loop cycl ;

mult_:
fld y
fld h
fmul
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 9.09.2012 19:04
Сообщение #8


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


С описанием
x dd 2.0
все итерации проходят (проверял 4 первых, дальше не хватило терпения, на выходе, после того как цикл завершился) имеем:


Эскизы прикрепленных изображений
Прикрепленное изображение
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 9.09.2012 21:08
Сообщение #9


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Цитата(IUnknown @ 9.09.2012 20:04) *

С описанием
x dd 2.0
все итерации проходят (проверял 4 первых, дальше не хватило терпения, на выходе, после того как цикл завершился) имеем:


Отлично, спасибо! Теперь начну увеличивать n, пока не достигну требуемой точности.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 10.09.2012 16:48
Сообщение #10


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Опять вынужден обратиться: программу продолжил, но новый фрагмент он не видит и сразу переходит к выводу на экран прежнего значения для n=20. Привожу листинг без процедуры вывода на экран:


.286p
.model small
.stack 100h
.data
a dw 2
b dw 5
x dd 2.0
n dw 20
d dw 20
h dq ?
y dq ?
y2 dq ?

.code
main proc
mov ax, @data
mov ds, ax
m1: mov CX, [n]
dec CX
finit
fild b
fisub a
fidiv n
fst h ;вычисляем шаг h

finit
fld1
fild b
fyl2x
fldln2
fmul ; вычиcляем ln 5
fld1
fdivr ;вычиcляем 1/ln 5
fild n
ficom d
jg m2
fxch
fstp y


fldln2
fld1
fdivr ; вычисляем 1/ln2
fadd y
fstp y
fild a
fld y
fdivr ;вычисляем (1/ln a + 1/ln b)/2
fstp y

cycl:
finit
fld x
fadd h
fst x ;производим приращение х и каждый раз

сохраняем

fld1
fld x
fyl2x
fldln2
fmul
fld1 ;
fdivr ;
fadd y
fstp y
loop cycl

mult_:
fld y
fld h
fmul ;когда х = 5, перемножаем на h
fst y

;повторяем то же для n=40
finit
fild n
fiadd d
fistp n
jmp m1
m2:
fxch
fstp y2


fldln2
fld1
fdivr ; вычисляем 1/ln2
fadd y2
fstp y2
fild a
fld y2
fdivr ;вычисляем (1/ln a + 1/ln b)/2
fstp y2

cycl2:
finit
fld x
fadd h
fst x ;производим приращение х и каждый раз

сохраняем

fld1
fld x
fyl2x
fldln2
fmul
fld1 ;
fdivr ;
fadd y2
fstp y2
loop cycl2 ;

mult2_:
fld y2
fld h
fmul ;61 когда х = 5, перемножаем на h
fst y2

fsub y
fabs

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 10.09.2012 20:12
Сообщение #11


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Во-первых, с чего ты решил, что вот это:
Цитата
fild n
ficom d
jg m2
сработает так, как ты задумал? Не будет этого. Это тебе не процессорные команды сравнения, чтоб можно было использовать любые сравнения. Общий шаблон - такой:

    fcomp x ; сравниваем верхушку стека с числом X
fstsw ax ; сохраняем слово состояния сопроцессора в AX
sahf ; заталкиваем AH в регистр флагов

; а теперь - внимание:
jp lbl_1 ; значения несравнимы
jc lbl_2 ; st(0) < x
jz lbl_3 ; st(0) = x
; Раз мы пришли сюда - значит st(0) > x
А во-вторых - зачем тебе все эти пляски с прыжками из одной части кода в другую? Сделай 2 нормальных вложенных цикла, изначально N присвой 0, и тут же его увеличивай на D, это будет внешний цикл. А внутренний - вычисление самого интеграла. Программа упростится донельзя (а если еще воспользоваться макросредствами ассемблера - у тебя же TASM, я правильно понимаю?) то все будет еще проще.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 11.09.2012 16:14
Сообщение #12


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Вот первоначальный вариант (можно еще дорабатывать)
.286p
.model small
.stack 100h
.data
a dw 2
b dw 5
x dq 2.0
n dw 0
d dw 20
h dq ?
y dq ?

.code

CalcF macro ; На вершине стека должен быть параметр
fld1
fld st(1)
fyl2x
fldln2
fmul
fld1
fdivr

endm

iCalcF macro param
fld1
fild param

fyl2x
fldln2
fmul
fld1
fdivr

endm

main proc

mov ax, @data
mov ds, ax

; начинаем цикл по увеличению N
mov cx, 3 ; Будут рассчитаны значения при N = 20, 40, 60
outer_loop:
push cx

mov cx, n
add cx, d
mov n, cx
dec cx

; вычисляем шаг
finit
fild b
fisub a
fidiv n
fst h ; Сохраняем шаг

iCalcF b ; 1 / ln b
fstp y
iCalcF a ; 1 / ln a
fadd y ; Складываем
fdiv x ; Делим сумму на 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 ; Домножаем на h - получаем искомое значение
call outfloat

pop cx
loop outer_loop;

exit:
mov ax, 4c00h ;
int 21h ;
main endp

; За кадром - реализация outfloat, распечатывающая содержимое
; вершины стека сопроцессора и выбрасывающая распечатанное
; значение из стека

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 11.09.2012 21:54
Сообщение #13


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Однако серьезно! Буду пробовать. Признателен)

Кстати, почему я организовал дополнительные циклы, и ввел переменную у2: необходимо найти решение с определенной точностью (0,0001). Для этого придется сравнивать значения F для каждых "соседних" n. Соответственно, если для каждого последующего n я записываю значения f в одну и ту же переменную у, то значения при меньшем n теряются. Попробую что-нибудь придумать.

Сообщение отредактировано: Hey - 11.09.2012 22:54
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 12.09.2012 18:11
Сообщение #14


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Цикл ему кажется слишком длинным: на инструкции loop outer_loop выдает "Relative jump out of range by 22h bytes". И почему-то стал ругаться на невинную команду fstsw ax: "Illegal immediate".

P.S. Я решил оформить макросом приращение n и вычисление h, прилагаю код целиком.




.model small
.stack 100h
.data
a dw 2
b dw 5
x dq 2.0
n dw 0
d dw 20
h dq ?
y dq ?

.code

CalcF macro; На вершине стека д.б. параметр
fld1
fld st(1)
fyl2x
fldln2
fmul
fld1
fdivr

endm

iCalcF macro param
fld1
fild param

fyl2x
fldln2
fmul
fld1
fdivr

endm

calc_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
; начинаем цикл по увеличению N
mov cx, 3 ; Будут рассчитаны значения при N = 20, 40, 60

outer_loop:
push cx
calc_h

iCalcF b ; 1 / ln b
fstp y
iCalcF a ; 1 / ln a
fadd y ; Складываем
fdiv x ; Делим сумму на 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
call outfloat

pop cx
loop outer_loop;

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)
; Точнее, стэков.

pop dx
pop cx
pop ax
ret
outfloat endp
exit:
mov ax, 4c00h ;
int 21h ;
main endp

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 12.09.2012 23:10
Сообщение #15


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Цитата
Цикл ему кажется слишком длинным: на инструкции loop outer_loop выдает "Relative jump out of range by 22h bytes". И почему-то стал ругаться на невинную команду fstsw ax: "Illegal immediate".
Ты б за структурой следил, и вторую процедуру записывал бы после того, как первая закончится - было бы меньше неожиданностей. Насчет цикла - не подтверждается, код прекрасно собирается (помнят еще руки-то smile.gif Цикл рассчитан до байта, добавляем еще одну инструкцию - 2 лишних байта для LOOP-а). На скрине - результат компиляции и запуска вот такого кода:

.286p
.model small
.stack 100h
.data
a dw 2
b dw 5
x dq 2.0
n dw 0
d dw 20
h dq ?
y dq ?
NL db 0Dh, 0Ah, "$"

.code

CalcF macro ; На вершине стека должен быть параметр
fld1
fld st(1)
fyl2x
fldln2
fmul
fld1
fdivr

endm

iCalcF macro param
fld1
fild param

fyl2x
fldln2
fmul
fld1
fdivr

endm

CalcH macro

mov cx, n
add cx, d
mov n, cx
dec cx
; вычисляем шаг
fild b
fisub a
fidiv n
fst h ; Сохраняем шаг

endm

main proc

mov ax, @data
mov ds, ax

; начинаем цикл по увеличению N
mov cx, 3 ; Будут рассчитаны значения при N = 20, 40, 60
outer_loop:
finit ; выносим инициализацию сюда
push cx
CalcH

iCalcF b ; 1 / ln b
fstp y
iCalcF a ; 1 / ln a
fadd y ; Складываем
fdiv x ; Делим сумму на 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 ; Домножаем на h - получаем искомое значение
call outfloat

pop cx
loop outer_loop;

exit:
mov ax, 4c00h ;
int 21h ;
main endp

; Требуется директива .286C или выше.
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
; Пояснение далее пойдёт на примере. ; ST(0) ST(1) ST(2) ST(3) ...
; Отделим целую часть от дробной. ; 73.25 ... что-то не наше
@of1: 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
; Поделим целую часть на десять,
@of2: fidiv word ptr [bp - 2] ; 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 word ptr [bp - 2] ; 3 1 7 0.25 ...
fistp word ptr [bp - 4] ; 1 7 0.25 ...
inc cx
; в стэке.
push word ptr [bp - 4]
fxch st(1) ; 7 1 0.25 ...
; Так будем повторять, пока от целой части не останется ноль.
ftst
fstsw ax
sahf
jnz short @of2
; Теперь выведем её.
mov ah, 02h
@of3: pop dx
; Вытаскиваем очередную цифру, переводим её в символ и выводим.
add dl, 30h
int 21h
; И так, пока не выведем все цифры.
loop @of3 ; 0 1 0.25 ...
; Итак, теперь возьмёмся за дробную часть, для начала проверив её существование.
fstp st(0) ; 1 0.25 ...
fxch st(1) ; 0.25 1 ...
ftst
fstsw ax
sahf
jz short @of5
; Если она всё-таки ненулевая, выведем точку
mov ah, 02h
mov dl, '.'
int 21h
; и не более шести цифр дробной части.
mov cx, 6
; Помножим дрообную часть на десять,
@of4: fimul word ptr [bp - 2] ; 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 word ptr [bp - 4] ; 1 0.5 ...
; и сразу выведем.
mov ah, 02h
mov dl, [bp - 4]
add dl, 30h
int 21h
; Теперь, если остаток дробной части ненулевой
fxch st(1) ; 0.5 1 ...
ftst
fstsw ax
sahf
; и мы вывели менее шести цифр, продолжим.
loopnz @of4 ; 0 1 ...
; Итак, число выведено. Осталось убрать мусор из стэка.
@of5: fstp st(0) ; 1 ...
fstp st(0) ; ...
; Точнее, стэков.
leave

mov ah, 9
mov dx, offset NL
int 21h

pop dx
pop cx
pop ax
ret
outfloat endp

end main


Сообщение отредактировано: IUnknown - 12.09.2012 23:11


Эскизы прикрепленных изображений
Прикрепленное изображение
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 13.09.2012 14:32
Сообщение #16


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Да, фрагмент с exit'ом я не туда вставил. Действительно работает, спасибо)). Вопрос: что означает строка NL db 0Dh, 0Ah, "$" ?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 13.09.2012 15:09
Сообщение #17


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Это для перевода строки: NewLine, символ CR = 13, символ LF = 10, и завершение строки - знак доллара smile.gif
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 14.09.2012 20:22
Сообщение #18


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


Решительно не хватает знаний, чтобы успешно завершить программу. Я ее расширил, чтобы n возрастало до тех пор, пока не будет достигнута требуемая точность (0.0001). Вместо вывода значения функции при каждом из n (20, 40, 60 ....) прога выводит окончательное значение, причем не один раз((. Вывод n также не работает. Прилагаю.



.286p
.model small
.stack 100h
.data
mes db 'Operands not comparable', 13, 10, '$'
a dw 2
b dw 5
x dq 2.0
n dw 0
d dw 20
eps dd 0.0001
h dq ?
y dq ?
z dq ?
NL db 0Dh, 0Ah, "$"


.code

CalcF macro; На вершине стека д.б. параметр
fld1
fld st(1)
fyl2x
fldln2
fmul
fld1
fdivr

endm

iCalcF macro param
fld1
fild param

fyl2x
fldln2
fmul
fld1
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_:
Сalc_h
iCalcF b ; 1 / ln b
fstp y
iCalcF a ; 1 / ln a
fadd y ; Складываем
fdiv x ; Делим сумму на 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

call outfloat
call OutInt ;выводим актуальное n
finit

; далее повторяем с начала, но сохраняем в z для последующего сравнения с y

Сalc_h
iCalcF b ; 1 / ln b
fstp z
iCalcF a ; 1 / ln a
fadd z ; Складываем
fdiv x ; Делим сумму на 2
fstp z ; Сохр. начальное приближение
fld x ;

lesser_loop:
fadd h ; X <- X + h
CalcF
fadd z
fstp z ; Сохраняем измененное значение интеграла
loop lesser_loop

fld z
fmul h

call outfloat

call OutInt ;выводим актуальное n

fld z
fsub y
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


OutInt proc near
xor ax,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
loop l2

mov AH,9
mov dx, offset NL
int 21h
ret
outint 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

end main


 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 15.09.2012 11:30
Сообщение #19


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Hey, я опять не понял, зачем тебе 2 цикла, в каждом из которых ты вычисляешь значения интегралов? Давай запишем алгоритм который тебе нужен, в псевдокоде. Итак, чтобы определить, при каком N значение интеграла найдено с точностью Eps, тебе достаточно:

   n <- 0
y <- 0.0;
repeat
prev <- y;
n <- n + DeltaN;
y <- Integral(a, b, n);
until abs(y - z) < eps;
print "finally Int = ", y, " when n = ", n


Всё, никаких двойных циклов, все прекрасно делается одним. А теперь смотри, как это записывается на ассемблере (я заменил переменную z на prev):

main proc
mov ax, @data
mov ds, ax

outer_:
fld y
fstp prev
; fldz
; fstp y

; вычисляем шаг для текущего N
Сalc_h

iCalcF b ; 1 / ln b
fstp y
iCalcF a ; 1 / ln a
fadd y ; Складываем
fdiv x ; Делим сумму на 2
fstp y ; Сохр. начальное приближение

; внутренний цикл - вычисляем интеграл
fld x ; X в стек сопроцессора
inner_loop:
fadd h ; X <- X + h
CalcF ; F(X)
fadd y
fstp y ; Сохраняем измененное значение интеграла
loop inner_loop

fld y
fmul h ; нашли окончательное значение при текущем N
fst y ; сохранили его назад в Y для последующего сравнения с prev

; дублируем значение с вершины стека
; fld st

; выводим значение интеграла и N
call outfloat
call OutInt ; выводим актуальное n

fld y
fsub prev
fabs
fcomp eps
fstsw ax
sahf
jp uncomp
jz m1
jc exit
m1:
jmp outer_
uncomp:
mov dx, offset mes
mov ah, 09
int 21h

exit:
mov ax, 4c00h ;
int 21h ;
main endp
Проще, правда, чем делать дважды одно и то же?

Теперь насчет
Цитата
Вывод n также не работает.
Процедуру OutInt проверять не пробовал? smile.gif

Вообще-то, она должна выглядеть так (вообще-то, жестко задавать в программе, что процедура выводит именно N - это бред, лучше перед ее вызовом занести ax <- N):

outint  proc    near
push cx
push dx
push bx
push ax

mov ax, n ; <--- !!! А этого лучше не делать !!!

; Проверяем число на знак.
test ax, ax
jns short @oi1
; Если оно отрицательное, выведем минус и оставим его модуль.
mov ah, 02h
mov dl, '-'
int 21h
pop ax
push ax
neg ax
; Количество цифр будем держать в CX.
@oi1: xor cx, cx
mov bx, 10
@oi2: xor dx, dx
div bx
; Делим число на десять. В остатке получается последняя цифра.
; Сразу выводить её нельзя, поэтому сохраним её в стэке.
push dx
inc cx
; А с частным повторяем то же самое, отделяя от него очередную
; цифру справа, пока не останется ноль, что значит, что дальше
; слева только нули.
test ax, ax
jnz short @oi2
; Теперь приступим к выводу.
mov ah, 02h
@oi3: pop dx
; Извлекаем очередную цифру, переводим её в символ и выводим.
add dl, 30h
int 21h
; Повторим ровно столько раз, сколько цифр насчитали.
loop @oi3

; переводим строку после выведенного числа
mov ah, 9
mov dx, offset NL
int 21h

pop ax
pop bx
pop dx
pop cx
ret
outint endp
С этими изменениями программа прекрасно отрабатывает:
F:\Asm30>trapece
2.5912
20
2.5898
40
2.5896
60
2.5895
80

F:\Asm30>

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Hey
сообщение 15.09.2012 17:36
Сообщение #20


Новичок
*

Группа: Пользователи
Сообщений: 15
Пол: Мужской

Репутация: -  0  +


IUnknown, ты прав: уперся я в свое решение как лунатик и увидеть больше ничего не мог). С одним циклом все внятно. Спасибо за терпениеsmile.gif. Еще вопрос: в какой программе ты набираешь листинг? Явно не блокнот.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

2 страниц V  1 2 >
 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 15.11.2024 11:01
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"