溢出整数的gfortran优化

时间:2014-03-17 13:42:25

标签: optimization random fortran gfortran

我已经"继承了"一个简单的同余伪随机数生成器,如下所示:

  subroutine ribm(rndm,ial)
    implicit none
    integer :: ial
    real :: rndm, al
    ial=ial*65539
    if(ial.lt.0) then
      ial=ial+2147483647+1
    endif
    al=ial
    rndm=al*0.4656613e-9
  end subroutine ribm

ial变量包含RNG种子,并在生成器外部初始化一次。像往常一样,生成器应该产生0到1之间的伪随机数。因此,ial必须始终保持非负面。代码尝试使用if语句强制执行此条件。

我使用以下程序测试发生器:

program testribm
  implicit none
  real :: r
  integer :: i
  data i /12345/

  call ribm(r,i)
  call ribm(r,i)
  call ribm(r,i)
  call ribm(r,i)
  call ribm(r,i)
  call ribm(r,i)
  print *,r,i
contains
  subroutine ribm(rndm,ial)
  ! [...]
  end subroutine ribm
end program testribm

如果我使用优化gfortran或更低的-O1 v4.8.2进行编译,我会得到:

 0.580895185      1247462939

OTOH,如果我使用-O2我得到:

-0.709615409     -1523887535

请注意负的种子值。优化会影响整数算术以及重复调用ribm的最终结果。

我知道如何解决/解决这个问题。我的问题是:这是一个gfortran错误吗?或者这种行为是由于代码是非标准的?但如果是这种情况,不应该gfortran产生一些警告信息吗?

3 个答案:

答案 0 :(得分:1)

优化可以改变实际完成的计算。如果结果更改为非标准计算(例如涉及整数溢出的计算),请不要感到惊讶。我建议在Fortran中使用无符号整数的算法是使用下一个更大的整数类型。例如,如果算法应使用无符号32位整数完成,请使用Fortran的带符号64位整数。

答案 1 :(得分:1)

我想补充一下M.S.B。答案,只有当编译器一次性优化对ribm的多次调用时才会出现问题。 (我以前的建议无效。)

但原始问题的答案。 我认为它不是编译错误。 2147483647+1只是超出范围。问题是为什么即使-pedantic -Wall -Wextra也没有警告。事实证明,@ Arek'如果需要-Wstrict-overflow,则仅在-Wstrict-overflow=1中包含-Wall

如果可能,我建议使用函数iandiorieorishft等类似于便携式结果,而不是算术。

答案 2 :(得分:0)

两个答案都很好,至于解决方案,我认为使用括号是防止编译器优化的正确方法吗?

subroutine ribm(rndm,ial)
implicit none
integer :: ial
real :: rndm, al
ial=ial*65539
if(ial.lt.0) then
  ial=(ial+1)+2147483647
endif
al=ial
rndm=al*0.4656613e-9
end subroutine ribm