为什么 floor(Infinity) 给出符号相反的大整数?

Why does floor(Infinity) give large integer with opposite sign?

以下 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 returns 是一个整数。

我不明白他们的符号...从数学上讲,数轴是:

-Infinity    -2147483648    0    2147483647    Infinity
--------------------------------------------------------->

但显然我的程序是相反的。 数学上来说,floor(inf)应该return(类型转换后)2147483647floor(-inf)应该return-2147483648.

符号变化的原因是什么? gfortran 使用什么约定来产生这个奇怪的结果? Fortran 中是否有更普遍的约定?

此外,其他进行类型转换的函数 return 奇怪(至少对我而言)值:

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

return这是一个非常奇怪的结果:

-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 - %d\n",iflr,irnd,icei);
   iflr = floor(-inf);
   irnd = round(-inf);
   icei = ceil(-inf);
   printf("%d - %d - %d\n",iflr,irnd,icei);
}

gcc test.c -lm 编译,它在所有情况下打印 -2147483648

数学上 floor(inf) 和 floor(-inf) 应该 return inf 和 -inf 因为用标量改变无限数仍然是无限的。

有趣的是,iFort 打印

 -2147483648
 -2147483648

与 gfortran 结果相反。

此外,您使用 iFort 编译的第二个测试程序打印:

-2147483648 -2147483648 -2147483648
-2147483648 -2147483648 -2147483648

这里真正的问题是 floor() 具体 return 是一个整数,没有 非规范化 整数,当然也没有可以存储值的特殊位模式作为整数中的 inf 或 NAN。没有这样的规范,它的程序员要小心了。