以下Fortran程序:
program test
double precision :: inf, one, zero
one = 1.d0
zero = 0.d0
inf = one/zero
write(6,*) floor( inf)
write(6,*) floor(-inf)
end program test
用gfortran test.f95
编译打印了这个:
-2147483648
2147483647
我理解为什么这些值,它们是 4 字节整数的最大值(或最小值),这是 gfortran 中的默认值,并且floor
返回一个整数。
我没有得到的是他们的标志...从数学上讲,数字线将是:
-Infinity -2147483648 0 2147483647 Infinity
--------------------------------------------------------->
但显然我的程序以相反的方式看待它。从数学上讲,floor(inf)
应该返回(类型转换后)2147483647
,floor(-inf)
应该返回-2147483648
。
什么原因导致标志的变化?gfortran 使用什么约定来得出这个奇怪的结果? Fortran 中是否有更普遍的约定?
此外,其他进行类型转换的函数返回奇怪的(至少对我来说)值:
write(6,*) floor( inf), nint( inf), ceiling( inf)
write(6,*) floor(-inf), nint(-inf), ceiling(-inf)
指纹:
-2147483648 0 -2147483647
2147483647 0 -2147483648
更新:
在 agentp 的评论之后,我发现这不仅仅发生在无穷大上。任何较大的数字(大于2^32
)都会给出相同的结果。
更奇怪的是,这个程序:
program test
real :: big
big = 2.d0**32-1000
print*, big
write(6,*) floor( big), nint( big), ceiling( big)
write(6,*) floor(-big), nint(-big), ceiling(-big)
end program test
返回这个非常奇怪的结果:
-2147483648 -1024 -2147483647
2147483647 1024 -2147483648
只是出于好奇,我检查了这个 C 程序:
#include <stdio.h>
#include <math.h>
int main()
{
float one = 1;
float zero = 0;
float inf = one/zero;
int iflr = floor(inf);
int irnd = round(inf);
int icei = ceil(inf);
printf("%d - %d - %dn",iflr,irnd,icei);
iflr = floor(-inf);
irnd = round(-inf);
icei = ceil(-inf);
printf("%d - %d - %dn",iflr,irnd,icei);
}
使用gcc test.c -lm
编译,它为所有情况打印-2147483648
。
数学上floor(inf) 和 floor(-inf) 应该返回 inf 和 -inf,因为用标量改变无限个数字仍然是无限的。
有趣的是,iFort 打印
-2147483648
-2147483648
与Gfortran的结果相反。
此外,使用 iFort 编译的第二个测试程序打印:
-2147483648 -2147483648 -2147483648
-2147483648 -2147483648 -2147483648
这里真正的问题是floor()专门返回一个整数,并且没有非规范化的整数,当然也没有特殊的位模式可以在整数中存储诸如inf或NAN之类的值。没有这样的规范,它的程序员要当心。