构建Romberg集成表

时间:2015-08-30 20:54:02

标签: math fortran gfortran numerical-integration numerical-analysis

我正在尝试编写Fortran程序来生成Romberg集成表。第4.5章的书中有数值分析由R.L.Burden和J.D.Faires第9版编写的算法。到目前为止,我已经写了这个

from scipy import ndimage
edge_horizont = ndimage.sobel(greyscale, 0)
edge_vertical = ndimage.sobel(greyscale, 1)
magnitude = np.hypot(edge_horizont, edge_vertical)

该程序提供以下输出:

implicit none
integer,parameter::n=4
real::a,b,f,r(n,n),h,sum1
integer::i,k,j,m,l
open(1,file='out.txt')
a=0.
b=1.
h=b-a
r(1,1)=.5*h*(f(a)+f(b))
write(1,*)r(1,1)
do i=2,n
    sum1=0.
    do k=1,2**(i-2)
        sum1=sum1+f(a+(k-.5)*h)
    enddo
    r(2,1)=.5*(r(1,1)+h*sum1)
    do j=2,i
        r(2,j)=r(2,j-1)+(r(2,j-1)-r(1,j-1))/(4**(j-1)-1)
        write(1,*)((r(m,l),m=2,2),l=1,i)
    enddo
    h=h/2.
    do j=1,i
        r(1,j)=r(2,j)
    enddo
enddo

end

real function f(x)
implicit none
real,intent(in)::x

f=1/(1+x**2)

end function

但它应该给出这个:

  0.750000000    
  0.774999976      0.783333302    
  0.782794118      0.785392165       3.56011134E-22
  0.782794118      0.785392165      0.785529435    
  0.784747124      0.785398126      0.785529435       7.30006976E+28
  0.784747124      0.785398126      0.785398543       7.30006976E+28
  0.784747124      0.785398126      0.785398543      0.785396457    

上面的一个是用Maple编写的程序完成的。 Maple的程序是

0.7500000000 
0.7750000000 0.7833333333 
0.7827941176 0.7853921567 0.7855294120 
0.7847471236 0.7853981253 0.7853985227 0.7853964451 
0.7852354030 0.7853981627 0.7853981647 0.7853981590 0.7853981659 

那么现在如何处理Fortran程序以获得与Maple程序相同的结果?

2 个答案:

答案 0 :(得分:4)

枫树计划和fortran源之间存在许多差异。

  • maple程序的结果数组的大小从0到n,而Fortran程序从1运行到n。

  • 由于固定列索引,Fortran源永远不会定义(计算值)r(3:,:)。

鉴于这些差异,结果不同应该不足为奇。

在考虑到浮点运算的常见变化后,将枫树源转换为F2008的天真,相对直接的转换得到了相同的结果。

module romberg_module
  implicit none

  integer, parameter :: rk = kind(1.0d0)

  abstract interface
    function f_interface(x)
      import :: rk
      implicit none
      real(rk), intent(in) :: x
      real(rk) :: f_interface
    end function f_interface
  end interface
contains
  function romberg(f, a, b, n) result(r)
    procedure(f_interface) :: f
    real(rk), intent(in) :: a
    real(rk), intent(in) :: b
    integer, intent(in) :: n
    real(rk) :: r(0:n,0:n)    ! function result.

    real(rk) :: h
    integer :: row
    integer :: col
    integer :: k

    h = b - a
    r(0,0) = h / 2 * (f(a) + f(b))
    do row = 1, n
      h = h / 2
      r(row, 0) = 0.5_rk * r(row-1, 0)  &
          + sum(h * [(f(a + (2 * k - 1) * h), k = 1, 2**(row-1))])
      do col = 1, row
        r(row, col) = (4**col * r(row, col-1) - r(row-1, col-1))  &
            / (4**col - 1)
      end do
    end do
  end function romberg

  subroutine print_table(unit, r)
    integer, intent(in) :: unit
    real(rk), intent(in) :: r(0:,0:)
    integer :: row
    do row = 0, ubound(r,1)
      write (unit, "(*(F13.10,1X))") r(row, :row)
    end do
  end subroutine print_table
end module romberg_module

program print_romberg_table
  use, intrinsic :: iso_fortran_env, only: output_unit
  use romberg_module
  implicit none
  real(rk), allocatable :: r(:,:)
  r = romberg(f, 0.0_rk, 1.0_rk, 4)
  call print_table(output_unit, r)
contains
  function f(x)
    real(rk), intent(in) :: x
    real(rk) :: f
    f = 1.0_rk / (1.0_rk + x**2)
  end function f
end program print_romberg_table

答案 1 :(得分:0)

你的程序太长了,只能通过阅读代码来调试(而且我已经超过5年了,我不会写一行f95),但从结果表中可以看出在F90中,实数变量表示为单精度(32位)IEEE 754浮点数,而枫木使用更高的精度。

实际上,32位精度0.775变为(约)0.77499998,而到64位则为0.77500000000000002。 完全错误的数字(例如3.56011134E-22)可能是由于下溢/溢出或取消。

您可以使用合适的编译器选项强制64位精度,或者通过指定适当的实际类型,请参阅http://fortranwiki.org/fortran/show/Real+precision

integer, parameter :: dp = kind(1.d0)
real(kind=dp) :: a