Fortran二分法实现中e0变量更新异常与打印输出异常问题
问题原因分析
1. e0未按预期更新的原因
- Fortran 77默认采用引用传递的方式传递参数,主程序中定义的初始区间变量
A=1d-1、B=9d-1被直接传入Bisection子程序后,子程序内对形参A、B的修改会直接同步到主程序的原始变量上。 - 第一次调用
Bisection的过程中,当前f1函数返回值恒为e0+1(始终为正),因此二分法判断逻辑会不断将左边界A更新为区间中点,第一次调用结束后主程序的A已经被修改到接近0.9的数值。 - 主程序中计算
e0的公式为e0 = i*(B-A)/10 + A,第一次循环后B-A的差值极小,因此后续循环计算出的e0都会接近0.9,不会按预期逐步增长。
2. 后续循环无"in"日志的原因
Bisection子程序中迭代次数niter的计算公式为niter = nint(log((B-A)/eps)/log(2.))+1,第一次调用结束后B-A已经小于设置的精度eps=10d-6,因此(B-A)/eps的值小于1,取对数后为负数,计算得到的niter会小于等于0。- Fortran中
do i=1,niter的循环逻辑在niter<1时会直接跳过循环体,因此后续调用Bisection时不会进入迭代循环,也就不会调用f1函数,自然不会打印"in"日志。
修复方案
- 每次调用二分法前重置搜索区间,不要使用主程序全局的
A、B变量作为计算e0和传入子程序的参数,或者将Bisection子程序中的区间参数改为局部变量,避免修改原始传入值:
! 示例修改:直接用常数计算e0、传入初始区间,不受子程序修改影响 do i=1,9 e0 = i*(9d-1 - 1d-1)/10 + 1d-1 print *, 'out', i, e0 call Bisection(1d-1,9d-1,eps,f1,niter,e1,e0) write (9,'(2(f10.5))') e0,e1 end do
- 在
Bisection子程序中添加对niter合法性的判断,避免迭代次数小于1的情况,同时将f1函数修改为实际需要求解的超越方程(当前f1返回值恒正,二分法永远无法找到根)。
内容的提问来源于stack exchange,提问作者Jordi Fuentes
相关产品推荐
相关产品推荐

