我们将在下面转向浮点运算,但让我首先处理您的一个误解。您在 write 语句中使用列表导向格式意味着编译器选择的写出变量的格式是编译器的选择;它不是由语言标准规定的。您对第二个*
inwrite(*,*)
的使用告诉编译器根据需要写出变量的值。gfortran
因此,您所拥有的并不是算术有问题的证据,而是和之间存在差异ifort
。如果我将您的 write 语句修改为
write(*,'(f21.18)') a
然后我的英特尔 Fortran 程序写道
0.900000000000000022
到控制台。
SO充满了因不熟悉浮点运算细节而引起的问题,所以我不打算写一篇论文,只是与您的问题相关的一些观察。
IEEE-754 64 位浮点数(这可能是您从声明中得到的real(kind=8)
)仅提供大约 16 位十进制数字的有用信息。实际上,由于它们是二进制的,并且在一个基数和另一个基数之间没有简单的对应关系,它实际上是 15.95 个十进制数字,许多用户将其四舍五入,从不查看浮点数中第 15 个有效数字之后的任何内容-点数的十进制表示。所以两者ifort
都gfortran
用尾随2
的 s 误导你。
IEEE-754 不仅定义了 fp 数的格式,还定义了一些舍入和算术运算的规则。一个精心编写的程序,它只使用那些算术运算(我认为还指定了平方根)并且关心舍入模式和舍入操作应该在两个不同的处理器上产生相同的结果。当然,没有多少有用的数值程序只限于基本的算术运算。
由于 2003 年标准 Fortran 包含了一个名为的内部模块ieee_arithmetic
,它使程序员可以直接访问其运行的硬件的底层 IEEE-754 功能——但请注意,它并不要求硬件具有任何此类功能。如果您的硬件提供了必要的支持,使用ieee_arithmetic
另一个称为您的内部模块ieee_exceptions
,您应该能够编写在两者下编译的程序,gfortran
并且ifort
在执行时,每个 fp 数的最后一位产生相同的结果。
您还需要熟悉您正在使用的编译器的优化选项和数值算术选项。大多数编译器都有一个选项,其含义是sacrifice IEEE compliance for speed
(因为ifort
我认为它是fp-model
)。一般来说,遵守 IEEE-754 的操作会减慢您的程序。