|
本帖最后由 sslchi 于 2014-11-19 22:24 编辑
写了一个简短的代码,用辛普森公式计算积分,一开始的时候觉得误差很大
后来发现是算法中的最后一步不对,文中有注释。当然这是最简单的一个,使用不方便。有没有更简洁、更容易调用的代码?
自适应格式需要用到递归(貌似递归很费时啊)。如果可以的话,怎么才使程序以一个函数为输入量??
这样的话就可以很方便的调用了(类似于matlab里面的函数句柄)。
另外的一个问题是,我发现精度只能达到 e-8 左右,这又是什么原因呢? 如何能够使精度达到最高呢(相同的节点个数)
[Fortran] 纯文本查看 复制代码 program main
!use mkl95_blas
integer,parameter :: M=100
real(kind=8)::N,f(M),d(M),res,s
s=sin(0.0)!计算在a处的值
N=M/1.0 !用于计算步长(步长之倒数)
f= (/(i,i=1,M,1)/)/N !计算节点
d=sin(f) !节点处的函数值
do counter=1,M,2 ! 计算奇数节点的累加值(0算第0个点)
s=s+d(counter)*4.0/6.0
end do
do counter=2,M-2,2 ! 将计算偶数节点的值累加(不包括最后一个节点)
s=s+d(counter)*2.0/6.0
end do
s=s+d(M)/6.0 !将最后一个节点加上去。。。就是这里忘了除以6
s=2*s/N
res=s-(cos(0.0)-cos(1.0)) !计算误差
write(*,*) res
read(*,*)
end
今天又参照Moler(matlab作者)的matlab程序写了一个自适应格式的辛普森公式,但是还是无法避免把被积函数封装到module里面去了,
另外,由于目前对Fortran语法不是很熟悉,所以并没有设置报错和默认的误差上限(tol),如果有人感兴趣,希望可以帮助改进,将被积函数
放到module外面,然后就可作为一个可以被其他程序随便调用的子程序存在(现在想要改变被积函数需要修改module),欢迎将修改精简的代码
和我分享[Fortran] 纯文本查看 复制代码 module Simpson
!________________________________________________________
! Code by sslchi @ 2014
! 您可以随意使用、修改,同时欢迎将改进精简的代码和我分享
!______________________________________________________
contains
recursive subroutine SimpRc(func,a,b,tol,fa,fc,fb,Q,fcount)
!_________________________________________________________
! 递归子程序,用复化辛普森公式计算函数func在区间[a,b]上的
! 黎曼积分,但是该程序没有提供判断积分是否可积,仅能用于
! 计算常积分
! call SimRc(func,a,b,tol,fa,fc,fb,Q,fcount)
! func 是外部函数(用于计算被积函数在x出的值call func(f,x)),
! a,b分别代表区间[a,b]的左右端点
! tol 表示绝对误差的上限
! fa,fb,fc 表示func 在a,b,c(a/2+b/2)处的函数值
! Q表示积分值,fcount表示所用节点个数
!_________________________________________________________
implicit real*8(a-z)
external func
integer :: fcount,ka,kb
h=b-a
c=(b+a)/2d0
call func(fd,(a+c)/2d0)
call func(fe,(c+b)/2d0)
Q1=h/6d0*(fa+4d0*fc+fb)
Q2=h/12d0*(fa+4d0*fd+2d0*fc+4d0*fe+fb)
del=dabs(Q1-Q2)
if(del<tol) then
Q = Q2 + (Q2 - Q1)/15 !Richard 外推法
fcount = 2;
else
call SimpRc(func, a, c, tol, fa, fd, fc, Qa,ka);
call SimpRC(func, c, b, tol, fc, fe, fb, Qb,kb);
Q = Qa + Qb;
fcount = ka + kb + 2
end if
end subroutine SimpRc
subroutine fun1(f,x)
!___________________________________________
!
!fun1用于计算函数f在x处的值
!call fun1(f,x)
!____________________________________________
implicit real*8(a-z)
f=sin(x)
end subroutine fun1
end module Simpson
program main
use Simpson
integer :: fcount
real(kind=8) a,b,c,fa,fb,fc,tol,Q
a=0d0
b=1d0
tol=1d-9
c = (a + b)/2d0
call fun1(fa,a)
call fun1(fc,c)
call fun1(fb,b)
call SimpRc(fun1, a, b, tol, fa, fc, fb,Q,k)
fcount = k + 3
res=Q-(cos(0d0)-cos(1d0))
write(*,*)res,fcount
end program main
|
|