【发布时间】:2016-02-24 09:50:53
【问题描述】:
现在我正在处理在我之前从事该项目的人的 Fortran 代码。代码比较大,这里就不提供了。在这段代码的很多地方,双精度值除以整数。即:
double precision :: a,c
integer :: b
a = 1.0d0
b = 3
c = a/b
这有时会导致比常规浮点数错误更严重的错误。我将为您复制粘贴其中一个错误:3.00000032899483。为了他的目的,这没问题,但对我来说,这个错误是可怕的。似乎 fortran 将实数除以整数,然后将数字扩大到双精度,添加一些随机的东西。如果我写的话当然可以处理:
c = a/(real(b,8))
所以,我可以做到,但是搜索他所有的代码需要很长时间。这就是为什么,我尝试用下一种方式重载 (/) 运算符:
MODULE divisionoverload
!-----------------------------------------------------
INTERFACE OPERATOR (/)
MODULE PROCEDURE real_divoverinteger
END INTERFACE OPERATOR ( / )
CONTAINS
!-----------------------------------------------------
DOUBLE PRECISION FUNCTION real_divoverinteger(a,b)
IMPLICIT NONE
DOUBLE PRECISION, INTENT (IN) :: a
INTEGER, INTENT(IN) :: b
real_divoverinteger = a/real(b,8)
END FUNCTION real_divoverinteger
END MODULE divisionoverload
但是 gfortran4.8 给我的错误清楚地表明这与内在除法运算符冲突:
MODULE PROCEDURE real_divoverinteger
1
Error: Operator interface at (1) conflicts with intrinsic interface
那么在不手动处理所有整数除法的情况下,我能做些什么来解决这个问题呢?
使用打印格式生成此类数字的代码:
hx = (gridx(Nx1+1)-gridx(Nx1))/modx)
do i = 2,lenx
sub%subgridx(i)=sub%subgridx(i-1) + hx
end do
!*WHERE*
!hx,gridx[1d array], sub%subgridx[1d array] - double precision
!modx, lenx - integer
打印代码
subroutine PrintGrid(grid,N)
integer, intent (in) :: N
double precision, dimension(N), intent (in) :: grid
integer :: i
print"(15(f20.14))", (grid(i), i=1,N)
print*, ""
end subroutine PrintGrid
解决方案: 我为这个问题道歉。我应该更仔细地阅读代码。我发现了一个错误。你得到的问题的重现是通过下一个方式得到的:
program main
double precision :: a
a = 1.0/3
print*, a
end program main
所以基本上,他正在执行实数/整数除法并将这个值分配给 real*8。我用这样的代码改变了一切:
program main
double precision :: a
a = 1.0d0/3
print*, a
end program main
它奏效了!非常感谢您的帮助,如果没有您的回答,我会更多地处理这个问题。
【问题讨论】:
-
我猜这里的“错误”应该读作“舍入误差”或类似的意思,对吧?当你说这个错误例如“3.00000032899483”时,这个值是从哪里来的?你是如何得到的?你是怎么打印出来的?
-
我添加了会产生此类错误的确切代码。不,在错误下,我不是指舍入错误。如果我将整数写为 real(b,8),我会看到像 3.0000000000000001 这样的数字,这可以被认为是舍入错误。如果将此数字与 3 与固有的 fortran 运算符“==”进行比较,您将得到 .true。还有 3.00000032899483 == 3.d0 = .false。
-
吉尔斯的回答是正确的。任何不以这种方式运行的 fortran 编译器都会被破坏。如果我将上面的代码 sn-p 变成一个完整的程序并写出 c 的值,我在使用 gfortran 4.8 编译时得到 0.33333333333333331。您能否显示一个完整的代码来显示您的问题并打印出值 3.00000032899483,好吗?
-
添加了我在帖子更新中提供的 real(8,modx) 后“治愈”的确切代码。 Gilles 的回答是对的,我写了同样的例程并得到了正确的答案。然而,当我运行他的程序时出现了问题。我将尝试提取有问题的代码并将其放在我的帖子中。
标签: fortran precision division fortran90