我正在尝试编写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程序相同的结果?
答案 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