Fortran 程序没有正确更新变量的值

Fortran program doesn't update a variable's value properly

我正在尝试在 Fortran 中实现二分法子例程来解决计算科学程序,而 Fortran 正在做一些奇怪的事情。因此,该程序的目标是找到某个参数 e0 的超越方程的解,该参数在 for 循环中每一步更新并传递给子例程。

问题是:

我已经使用 Fortran77 进行数值求解几年了,从来没有遇到过这样的事情,但是我已经将近 6 个月没有编程了,所以也许我错过了一个重要的事情。

代码:

       program roots
       implicit none
       double precision A,B,eps,e0,e1
       integer i,niter
       external f1
       A = 1d-1
       B = 9d-1
       eps = 10d-6
       open(9,file='dades.dat',status='old')
       
       do i=1,9
       e0 = i*(B-A)/10 + A
c      Here is the first print. 'Out' meaning outside the subroutine
       print *, 'out', i, e0
       call Bisection(A,B,eps,f1,niter,e1,e0)
       write (9,'(2(f10.5))') e0,e1
       end do
       
       close(9)
       end program roots
       
       subroutine Bisection(A,B,eps,f,niter,xroot,e0)
       implicit none
              double precision A,B,eps,xroot,fuc,fua,e0
              integer niter,i
              niter = nint(log((B-A)/eps)/log(2.))+1
              
              do i=1,niter
                     xroot = (A+B)/2
c      Here the subroutine which uses e0 is called twice
                     call f(xroot,fuc,e0)
                     call f(A,fua,e0)
                     if (fuc .eq. 0) return
                     if (fuc*fua .lt. 0.) then
                            B = xroot
                     else
                            A = xroot
                     end if
              end do
              return
       end subroutine Bisection
       
       subroutine f1(x,f,e0)
       implicit none
       double precision x,f,e0
c      Here is the second print. 'In' meaning inside the subroutine
       print *, 'in', e0
       f = e0+1
       end subroutine f1

输出:

out           1  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 in  0.17999999999999999
 out           2  0.89999511718750003
 out           3  0.89999572753906254
 out           4  0.89999633789062505
 out           5  0.89999694824218746
 out           6  0.89999755859374997
 out           7  0.89999816894531248
 out           8  0.89999877929687500
 out           9  0.89999938964843751

深入查看代码后,我终于找到了问题所在。问题是变量 AB 都是输入和输出,因为它们在子程序内部被修改。因此,当第一次调用子程序时,它会更改 AB 的值(这与代码开头设置的值不同)。其余都是由此引发的问题。
解决方案是在每次迭代开始时重置值,如下所示:

       program roots
       implicit none
       double precision A,B,eps,e0,e1
       integer i,niter
       external f1
       eps = 10d-6
       open(9,file='dades.dat',status='old')
       
       do i=1,9
       A = 1d-1
       B = 9d-1
       e0 = i*(B-A)/10 + A
c      Here is the first print. 'Out' meaning outside the subroutine
       print *, 'out', i, e0
       call Bisection(A,B,eps,f1,niter,e1,e0)
       write (9,'(2(f10.5))') e0,e1
       end do
       
       close(9)
       end program roots
       
       subroutine Bisection(A,B,eps,f,niter,xroot,e0)
       implicit none
              double precision A,B,eps,xroot,fuc,fua,e0
              integer niter,i
              niter = nint(log((B-A)/eps)/log(2.))+1
              
              do i=1,niter
                     xroot = (A+B)/2
c      Here the subroutine which uses e0 is called twice
                     call f(xroot,fuc,e0)
                     call f(A,fua,e0)
                     if (fuc .eq. 0) return
                     if (fuc*fua .lt. 0.) then
                            B = xroot
                     else
                            A = xroot
                     end if
              end do
              return
       end subroutine Bisection
       
       subroutine f1(x,f,e0)
       implicit none
       double precision x,f,e0
c      Here is the second print. 'In' meaning inside the subroutine
       print *, 'in', e0
       f = e0+1
       end subroutine f1