gfortran在整数和实数计算中的精度损失

问题描述 投票:2回答:1

我正在移植一些以前在IBM AIX 4.3机器(IBM XL Fortran)上运行的旧Fortran代码。我在旧版代码中进行了以下计算,当在运行CentOS 7.7的x86_64机器上使用gfortran进行编译时,该代码会产生错误的答案。

ISCRATCH2 = ISCRATCH2 + (7 * (2.**16)) + TEMP2

ISCRATCH2的初始值为X'0B000000',而TEMP2的值为4053。计算结果为X'B070FD0',应为X'B070FD5'。如果我从2中删除点(使其成为整数而不是实数),则该值正确。这是一个演示问题的小程序。

      program main
      implicit none

      Integer*2 TEMP1
      Integer*2 TEMP2
      Integer*4 ISCRATCH1
      Integer*4 ISCRATCH2
      Integer*4 ISCRATCH3

      ISCRATCH1 = X'0B000000'
      ISCRATCH2 = X'0B000000'
      TEMP1 = 4053
      TEMP2 = 4053

      ISCRATCH3 = 7 * (2.**16)
      ISCRATCH3 = X'0B000000' + ISCRATCH3 + TEMP2

      ISCRATCH1 = ISCRATCH1 + (7 * (2**16)) + TEMP1

      ISCRATCH2 = ISCRATCH2 + (7 * (2.**16)) + TEMP2

      Print 1102, ISCRATCH1, TEMP1
1102  FORMAT('ISCRATCH1 is ', Z8, ' and TEMP1 is ', Z8)

      Print 1103, ISCRATCH2, TEMP2
1103  FORMAT('ISCRATCH2 is ', Z8, ' and TEMP2 is ', Z8)

      Print 1104, ISCRATCH3, TEMP2
1104  FORMAT('ISCRATCH3 is ', Z8, ' and TEMP2 is ', Z8)

  end program main

当我运行上面的程序时,它给出以下输出

ISCRATCH1 is  B070FD5 and TEMP1 is      FD5
ISCRATCH2 is  B070FD0 and TEMP2 is      FD5
ISCRATCH3 is  B070FD5 and TEMP2 is      FD5

如果我添加

-ffpe-trap=inexact

对于编译器选项,在第20行出现浮点异常。

这是预期的行为吗?如果是这样,为什么将它分成多行(ISCRATCH3计算),为什么它会得到正确的答案并且不引发浮点异常?我在CentOS 7.7上使用gfortran 4.8.5-39。这段代码似乎可以在IBM编译器上正常工作。我意识到以这种方式混合数据类型有点愚蠢,可以通过更改代码来解决。但是,在大型程序的整个代码中,很多地方都使用这种东西。我可以做些什么来解决此问题,而不必查找每个实例吗?

fortran gfortran
1个回答
-1
投票

[经过更多的实验后,问题似乎是(除了代码格式不正确的事实之外),增加了0x0B000000,并且该数字超出了@steve所建议的32位浮点数的精度。我认为原始语句中发生的事情是,由于其中一个值是实数,因此在赋值期间将答案转换回整数之前,会将它们全部转换为实数。

[为了进一步说明执行ISCRATCH4 = 184549376 + 10.的问题,结果为184549392,其中ISCRATCH4 = 184549376 + 10的结果为184549386。有趣的是,ISCRATCH4 = 184549376 + 1.仅返回184549376。如果将ISCRATCH4从,Integer * 4更改为Real * 4,则所有表达式均返回正确的答案。

我发现,如果将-fdefault-real-8添加到编译选项中,则答案始终是正确的,并且浮点异常消失了。我之所以这么认为是因为0x0B000000(或184549376)常数的实数转换现在足够大,可以容纳数字而不会降低精度。此修复程序应适用于我的应用程序。除了增加内存使用率之外,是否有任何其他原因?

© www.soinside.com 2019 - 2024. All rights reserved.