fortran 编译出现NAN的问题

专栏 / fortran 编译出现NAN的问题

fortran 编译出现NAN的问题

2022-04-28 11:48 --阅读 · --喜欢 · 早晨不想从快乐开始
粉丝: 530 文章: 65

1.  gfortran在生成real*8类型的数组时,即使显示的去初始化,并不是默认的全是0,有一小部分数据是很小很小的非零数据,还有很小几率是NaN。上网得知在一些如0/0的计算和以z开头的常量会得到NaN。解决办法是加入-finit-real=nan选项,这样生成的数组就全是NaN。然后再赋值为0就是全是0了。

2. 就是产生了数学错误,导致计算出的数非数。(NaN = Not a Number)
目测错误发生在
s=s*(t-x(j))/(x(i)-x(j))
当 i=1,j=3 时,x1 - x3 = 0-0 = 0
除法分母为0

3.

在进行数值计算的时候,不可避免地会出现数值问题。比如,对复数开根号,sqrt(-1);或者出现无穷大的数值,就像1.0/0.0 这样的情况。前者会导致Fortran显示 NaN 的结果(not a number),后者会显示 infinity 的结果。

比如,我有个数列,x,包含了5个数字,其中第3个数字无穷大,第4个数字无穷小。Fortran代码和结果显示如下:

在以上代码中,huge()命令会给出最大的real type中最大的数。这里乘以10倍,超出了最大范围,所以Fortran显示Infinity。

在实际运行代码进行迭代计算的时候,我们希望一旦出现NaN或者Infinity的时候,代码能够停下并显示错误。遗憾的是Fortran无法自动识别NaN或者Infinity,所以需要用户在代码里进行处理。

对于NaN的情况,我们可以通过判断数值是否等于它本身来确认NaN;而对于Infinity的情况,我们可以通过判断这个数是否超过了极值,也就是最大值huge(1.0)或者最小值-huge(1.0)。在刚才的代码中加入如下判断语句:以上代码的作用是:一旦出现了NaN或者Infinity,代码就报错并且离开循环,否则,循环继续。我们对这段代码进行测试,先测试Infinity的情况:

Infinity出现在数列的第三个位置,所以代码跑到第三个数时发现问题,离开了循环。接下来测试NaN。

NaN出现在数列的第四个数,所以代码跑到第四个数时发现问题,离开了循环。

有些数值问题对精度有较高的要求,所以需要用到双精度。我们把以上代码的第6行、第9行、第18行进行修改,然后运行代码,得到如下结果:

以上代判断出了数列中的第3个数是Infinity,并且停止了循环,但是总觉得这个结果有点怪怪的。问题在哪???

x数列的第三个数是:3.4...E+039,这不是我们预想的数值,这是单精度的最大值乘以10倍。对于双精度函数,最大值应该是1.797...E+308。上图的第9行,huge(1.0)给出的是单精度的最大值,然后乘以了双精度的10.d0,所以 x(3) 还是一个双精度的数。也就是说,我们误用了单精度的值判断双精度的数,然后还达到了我们预想的效果。这是数值模拟中偶见的“狗屎运”。为了统一双精度,修改上图中的第9行和第18行的huge(1.0) 为 huge(1.d0),如下:

在使用Fortran计算数值问题的时候,最好统一使用同一种精度的数值,避免不必要的麻烦。

除了自己写算法,还可以使用内置的module:IEEE_ARITHMETIC。该module包含了IEEE_IS_FINITE和IEEE_IS_NAN两个function。使用方法如下:

为了在出现 NaN 或者 Infinity 时就跳出循环,结合exit 命令使用:

4.我不清楚你myf2.dat文件里的数据时什么,但
un1=un1*(2*n-1)
un2=un2*(2*n)
这样算会出现无穷。

如果你那do while的循环计算30次,那么
un2=2^30*30!
这在计算机里是没法表示的。
你范围的界定是对un的绝对值进行界定,你可以试一下将eps值改大(如1e-2)就行了。

5 NaN是Not a Number的意思。如2/0的结果就是NaN。

总结

总结起来就这几个原因,一个是太大了,一个是分母出现零,两种情况。


投诉或建议