fortran 90中的数字配方ran_init整数模型假设

时间:2016-09-09 17:17:22

标签: integer fortran numerical-recipes

Numerical Recipes的ran_init子程序包含以下行:

INTEGER(K4B) :: new,j,hgt
...                                                                                            
hgt=hg 
...
if (hgt+1 /= hgng)    call nrerror('ran_init: arith assump 3 fails')

K4Bhgnghg在模块中通过以下方式全局声明:

INTEGER, PARAMETER :: K4B=selected_int_kind(9) 
INTEGER(K4B), PARAMETER :: hg=huge(1_K4B), hgm=-hg, hgng=hgm-1 

问题在于,在一台特定的计算机中(但在其他计算机中),我收到错误ran_init: arith assump 3 fails。我从有关此错误的文档中获得的唯一内容是:

  

这里有一点脏衣服!我们正在测试是否最积极   当1为1时,整数hg回绕到最负的整数hgng   添加到它。我们不能只写hg + 1,因为有些编译器会   在编译时评估它并返回溢出错误消息。   如果你的编译器看到临时的游戏   变量hgt,你必须找到另一种方法来欺骗它!

我怎么欺骗它?

1 个答案:

答案 0 :(得分:0)

崩溃的直接原因:

优化步骤中的编译器可以很容易地证明hgt+1hgng不能相同,因此它将整个条件优化为.false.。添加两个正整数不能创建负整数。

您可以通过使用较小级别的优化或通过一些伪装临时变量来避免它,这将比他们在旧的数字食谱中所做的更精细。您可以尝试使用-fwrapv-fno-strict-overflow标记。但它非常不确定,只能在具有某些编译器标志的给定版本的编译器中工作。

最简单的"修复"可能只是删除违规检查。它很可能在许多情况下工作(并且在其他情况下非常失败)。

解释和解决方案:

什么数字食谱对Fortran的标准有所作为。他们假设如果你将1加到最大的整数,你会得到最低的整数。

这对于Fortran整数是不允许的,也不允许在C中使用有符号整数。只允许在C中使用无符号整数,而Fortran没有这些整数。

因此编译器可以安全地假设添加两个正整数永远不会产生负整数。有关这些优化的详细讨论,请参阅https://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475

一种选择是重写可能导致C溢出的操作,并使用转换为无符号整数。我在我使用的随机数生成器中使用它(基于http://www.cmiss.org/openCMISS/wiki/RandomNumberGenerationWithOpenMP):

#include <stdint.h>
#include <memory.h>

int32_t sum_and_overflow (int32_t a, int32_t b)
{
  uint32_t au, bu, su;
  int32_t s;

  memcpy(&au, &a, sizeof(a));
  memcpy(&bu, &b, sizeof(b));
  su = au + bu;
  memcpy(&s, &su, sizeof(s));
  return s;
} 

使用Fortran接口

interface
  function sum_and_overflow(a, b) result(res) bind(C, name="sum_and_overflow")
    use, intrinsic :: iso_c_binding
    integer(c_int32_t) :: res
    integer(c_int32_t), value :: a, b
  end function
end interface

而不是

c = a + b

我打电话

c =  sum_and_overflow(a, b)

所以在你的情况下

if (sum_and_overflow(hgt,1) /= hgng) ...

但不仅仅是那里,你必须至少再多一个地方,这个假设在发电机中使用。在我使用的发生器中只有一条这样的线。

还有许多其他黑客可能会导致临时成功,但稍后会因其他一些编译器选项而失败。例如,GCC中未定义的行为清理不像Fortran和C中的有符号整数溢出,如果你这样做将终止你的程序。

这就是为什么我试图展示一个更复杂的解决方案,但不是围绕标准工作,而是遵循它。