着名的线性同余随机数发生器也称为最小标准使用公式
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,808
到9,223,372,036,854,775,807
,这比16807*x(i)
大得多。
不可能直接实现方程(7.1.2)和(7.1.3) 在高级语言中,由于a和m - 1的乘积超过了 32位整数的最大值。
那么为什么我们不能直接使用Integer(8)
类型来实现公式?
答案 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)
如果您的超级现代编译器没有向后兼容性。