自動變步長Simpson積分方法函數

Module mod
  Implicit none
  Real(kind=8), parameter :: a = 1.d0, b = 1.02d0  !// 積分區間
  Real(kind=8), parameter :: eps = 1.d-15  !// 誤差控制
  Real(kind=8) :: s  !// 最終積分結果
  Integer :: n  !// 最終分的份數
Contains
Subroutine solve( s, a, b, tol, n )
!//  Purpose   :  自動變步長Simpson積分方法函數
!    
!//  Input  parameters  :
!//       1.  func 外部函數
!//       2. 
!//       3.  a,b積分區間
!//       4.  tol  積分誤差容限
!
!//  Output parameters  :
!//       1.   s  積分結果
!//       2.   n  實際區間劃分個數
  Real(kind=8) :: s, s1, a, b, del, tol
  Integer :: n, i, m

  !//初始劃分40個子區間
  n = 40  !//n可以根據被積函數的複雜程序適當地減小或增大

  !//最大允許劃分100次
  m = 100  !//此處的m也可以根據被積函數的複雜程序適當地減小或增大
  Do i = 1, m
    call simp( s, a, b, n ) 
    n = n * 2
    call simp( s1, a, b, n )
    del = abs(s-s1)

    !//滿足精度後就停止循環
    if ( del < tol ) exit
  End do

  s = s1

end subroutine solve

Subroutine simp( s, a, b, n )
  Real(kind=8) :: s, a, b, h, f1, f2, f3, f4, t1, t2
  Integer :: n, k

  s = 0d0
  h = (b-a) / n / 2d0

  call func1( f1, a )
  call func1( f2, b )

  s = f1 + f2

  !//k=0 情況
  call func1( f1, a+h )
  s = s + 4d0*f1

  Do k = 1, n-1
    t1 = a + (2d0*k+1.d0) * h
    t2 = a + 2d0 * k * h

    call func1( f3, t1 )
    call func1( f4, t2 )

    s = s + f3*4d0 + f4*2d0  
  End do

  s = s*h / 3d0

End subroutine simp


Subroutine func1( f, x )
  Implicit none
  Real(kind=8) :: f, x
  f = -10.d0 * x**(-11.d0) !//被積函數(原函數的導數)
End subroutine func1

End module mod

Program main  !// 此程序一般只需更改積分區間[a,b],誤差限度eps,以及被積函數fun1
  use mod
  call solve( s, a, b, eps, n )
  write( *,'(1x,"區間劃分等份爲:",I5,/,1x,"積分結果爲:",g0)' ) n, s
  write( *,'(1x,"精確積分爲:",g0)' ) 1.02d0**(-10.d0) - 1.d0
End program main

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章