实型变量累加小数值无变化?gfortran代码输出异常求助
问题原因分析
你的判断是正确的,该问题确实由单精度实型变量的精度限制导致,结合你的代码逻辑,具体原因如下:
- 精度限制问题
你声明的real*4为单精度浮点数,仅能提供约6~7位十进制有效数字的精度,可表示的相邻两个浮点数的间隔会随数值本身的大小成正比增大:数值为x时,单精度的最小可分辨间隔约为x * 1.19e-7。
- 当x=1.0时,最小可分辨间隔约为1.19e-7,和你每次累加的1e-7非常接近,刚好可以识别到增量,因此
Numone可以正常累加。 - 当x=2.0时,最小可分辨间隔约为2*1.19e-7≈2.38e-7,远大于你每次累加的1e-7,这就导致你每次执行
Numtwo = Numtwo+1.e-7时,新增的量小于当前数值下的最小可分辨间隔,计算机会认为数值没有变化,Numtwo永远停留在2.0。
- 循环逻辑的放大作用
你用do while (Numone < 1.1 .and. Numtwo<2.1)作为循环停止条件,由于Numtwo永远为2.0,第二个判断条件永远成立,循环会一直执行到Numone累加到1.1才停止,最终输出就是你遇到的1.1和2.0的结果。
修复方案
- 优先更换更高精度的实型声明:可以使用双精度
real*8(更规范的Fortran标准写法可以引入内置模块use iso_fortran_env, only: real64后声明为real(real64)),双精度的最小可分辨间隔在数值为2时约为4.4e-16,远小于1e-7,可以正常识别累加的小数值。 - 你的需求是固定循环1000万次,建议直接使用固定次数的do循环,避免受精度问题影响循环次数,写法参考:
integer :: i do i = 1, 10000000 Numone = Numone + 1.e-7_dp ! 后缀_dp对应双精度常量,避免隐式类型转换 Numtwo = Numtwo + 1.e-7_dp end do
内容的提问来源于stack exchange,提问作者Nik Wrye
相关产品推荐
相关产品推荐

