我正在使用Codeblocks + GNU Fortran。
问题是我的计算如下:
SQRT(1-COS*COS)
当我做这些计算很多(几百万次)时,有时平方根下的值是负的,因此我得到NaNs的结果。
我的努力表明,当计算负数的平方根时,COS等于“-1”。因此,fortran错误地计算-1 * -1,因为在平方根下应该有0但是没有。
有没有办法解决这个问题?这不仅涉及毕达哥拉斯三角恒等式,而且还涉及平方根看起来像
的任何东西SQRT(1-x*x)
X在[-1,1]范围内。
基本上COST在我的程序中就是这样定义的(我为COST本身之前的一些冗长的介绍道歉,但事情就是如此):
XDET = 0.
YDET = 0.
ZDET = 50.
RADIUS = 1.
x = RADIUS*sqrt(omega) !omega=random number in uniform distribution [0,1]
y = 0.
z = 1.E-20
DW=SQRT((XDET-X)**2+(YDET-Y)**2+(ZDET-Z)**2)
DWW = 1./DW
AN2=(ZDET-Z)*DWW
COST = AN2
if(COST > 1. ) COST = 1.
if(COST < -1.) COST = -1.
SINT = SQRT(1.-COST*COST)
顺便说一句,AN2有时会假设一个绝对零,导致NaNs也被困在它之前。
P.S。我也有一个EXP(X)的错误,X高于90,显示为INFINITY。
答案 0 :(得分:1)
您的PS识别为错误的解释很简单
exp(90.0) > 3.4028235 x 10^38
和3.4028235 x 10^38
是单精度浮点数可以任意精度表示的最大正数。
当然,这种分析假设您的变量x
是IEEE 32位浮点数。
另请注意,表达式ZDET-Z
绝不会以单精度与1.0
不同。 1.0 - 1.0e-20 == 0.9999999999999999999
但是代表这个确切地超出了可用的精度,并且数字四舍五入为1.0
。
虽然我仍然看不出1.-COST*COST
怎么会消极,但你使用浮点运算并不能让我放心,在你没有显示的代码部分中没有细微的错误我们。
答案 1 :(得分:0)
我的猜测是由于浮点数的精度有限。看看这里:What Every Computer Scientist Should Know About Floating-Point Arithmetic。
简单的解决方案:
xx = x*x
if ( xx .gt. 1.e0 ) xx = 1.e0 ! 1.d0 for double precision
y = sqrt( 1.e0 - xx ) ! Again, 1.d0 for double precision
或者,作为一个单行:
y = sqrt( 1.e0 - min( x*x, 1.e0 ) )