我正在努力移植一些以前在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编译器上正常工作。我意识到以这种方式混合数据类型有点愚蠢,可以通过更改代码来解决。但是,在大型程序的整个代码中,很多地方都使用这种东西。我可以做些什么来解决此问题,而不必查找每个实例?
答案 0 :(得分:-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)常数的实数转换现在足够大,可以容纳该数字而不会降低精度。此修复程序应适用于我的应用程序。除了增加内存使用量之外,是否有任何其他原因?