随机数生成器溢出,4字节与8字节整数

时间:2016-07-21 03:45:54

标签: random fortran

着名的线性同余随机数发生器也称为最小标准使用公式

x(i+1)=16807*x(i) mod (2^31-1)

我想使用Fortran实现这一点。

但是,正如“Numerical Recipes”所指出的,直接用默认的Integer类型(32bit)实现公式会导致16807*x(i)溢出。

因此,本书推荐Schrage的算法基于m的近似因子分解。此方法仍可使用默认整数类型实现。

但是,我想知道fortran实际上有Integer(8)类型,其范围是-9,223,372,036,854,775,8089,223,372,036,854,775,807,这比16807*x(i)大得多。

但这本书甚至说了下面的句子

  

不可能直接实现方程(7.1.2)和(7.1.3)   在高级语言中,由于a和m - 1的乘积超过了   32位整数的最大值。

那么为什么我们不能直接使用Integer(8)类型来实现公式?

2 个答案:

答案 0 :(得分:2)

是否可以使用8字节整数取决于您的编译器和系统。您可以使用selected_int_kind方法获取具有特定范围的int类型。这段代码在我的64位计算机上编译并正常工作:

program ran
    implicit none
    integer, parameter :: i8 = selected_int_kind(R=18)
    integer(kind=i8) :: x
    integer :: i
    x = 100
    do i = 1, 100
        x = my_rand(x)
        write(*, *) x
    end do

    contains
        function my_rand(x)
            implicit none
            integer(kind=i8), intent(in) :: x
            integer(kind=i8) :: my_rand
            my_rand = mod(16807_i8 * x, 2_i8**31 - 1)
        end function my_rand
end program ran

答案 1 :(得分:0)

是。最简单的方法是将_8附加到整数常量,使它们成为8个字节。我知道它是“旧式”Fortran,但它是可移植且毫不含糊的。

顺便说一下,当你写:

16807*x mod (2^31-1)

这相当于取16807*x的结果并使用带有32位掩码的and,其中所有位都设置为1,除了符号位。 通过避免使用昂贵的mod函数来编写它的有效方法是:

iand(16807_8*x, Z'7FFFFFFF')

评论后更新

iand(16807_8*x, 2147483647_8)

如果您的超级现代编译器没有向后兼容性。