我已经编写了一个简短的蒙特卡罗积分算法来计算Fortran 90中的积分。我曾经使用内在随机数生成器和随机数生成器方法ran1对比了使用求解积分得到的结果。 Fortran90第2卷的数字配方。
运行相同的算法两次,一次调用内在的random_seed(),然后总是调用random_number(),并且一旦调用了Numerical Recipe书中提供的ran1()方法,我得到的结果是原理相同的形状,但内在的结果与ran1结果形成对比的是连续曲线。在这两种情况下,我使用随机参数调用函数10,000次作为参数值q,添加它然后继续下一个q值并调用函数10,000次等。
如果我增加调用次数,则曲线会收敛。但我想知道:为什么内在随机数发生器会产生这种平滑性?是否仍然建议使用它或是否有其他更多建议的RNG?我认为连续的结果是" less"内在数字生成器的随机性。
(我遗漏了源代码,因为我不认为它有很多输入。如果有人关心,我可以在以后提交。)
答案 0 :(得分:8)
标准Fortran中对伪随机生成器的质量没有任何保证。如果您关心密码学或对随机数敏感的科学的某些特定质量(蒙特卡罗),您应该使用一些您可以控制的库。
您可以研究编译器的手册,找出它对随机数生成器的说法,但每个编译器都可以实现完全不同的算法来生成随机数。
数字数据社区http://www.uwyo.edu/buerkle/misc/wnotnr.html
中的某些人实际上并没有很好地接受数字食谱此网站不是软件推荐,而是本文(roygvib在评论中给出的链接):https://arxiv.org/abs/1005.4117是一个很好的评论,包含错误和良好算法的示例,如何测试它们的方法,如何生成任意数字的分布和C中两个示例库的调用示例(其中一个也可以从Fortran中调用)。
我个人使用这个https://bitbucket.org/LadaF/elmm/src/e732cb9bee3352877d09ae7f6b6722157a819f2c/src/rng_par_zig.f90?at=master并行PRNG,但我没有测试质量,我个人只需要速度。但这不是软件推荐网站。
答案 1 :(得分:1)
我同意Vladamir F.但是......
为了帮助您寻找更好的随机数,请考虑最近添加到C ++ C++11 Pseudo Random Number Generators。 Mersenne twister和很多其他人都在那里。这是一个经过深思熟虑的系统。我看到两种方法可以测试这些序列:
我更喜欢第二种,因为绑定有点棘手,我准备了一个例子。文件是:
#ifndef CXX11_RAND_H
#define CXX11_RAND_H
void cxx11_init();
double cxx11_rand();
#endif
#include <algorithm>
#include <cstdio>
#include <memory>
#include <random>
#include <set>
#include <vector>
#include <chrono>
#include <thread>
#include <iostream>
#include "cxx11_rand.h"
static std::unique_ptr<std::uniform_real_distribution<>> dist;
static std::unique_ptr<std::mt19937_64> eng;
void cxx11_init(){
eng = std::unique_ptr<std::mt19937_64>( new std::mt19937_64(std::random_device{}()) );
dist = std::unique_ptr< std::uniform_real_distribution<> >( new std::uniform_real_distribution<>(0.0,1.0) );
}
double cxx11_rand(){
return (*dist)( *eng );
}
#include "cxx11_rand.h"
#ifdef __cplusplus
extern "C" {
#endif
void c_init(){
cxx11_init();
}
double c_rand(){
return cxx11_rand();
}
#ifdef __cplusplus
}
#endif
module f_rand_M
implicit none
!define fortran interface bindings to C functions
interface
subroutine fi_init() bind(C, name="c_init")
end subroutine
real(C_DOUBLE) function fi_rand() bind(C, name="c_rand")
use ISO_C_BINDING, only: C_DOUBLE
end function
end interface
contains
subroutine f_init()
call fi_init()
end subroutine
real(C_DOUBLE) function f_rand()
use ISO_C_BINDING, only: C_DOUBLE
f_rand = fi_rand()
end function
end module
program main
use f_rand_M
implicit none
integer :: i
call f_init()
do i=1,10
write(*,*)f_rand()
end do
end program
您可以使用以下GNU命令编译/链接
echo "compiling objects"
g++ -c --std=c++11 cxx11_rand.cpp c_rand.cpp
gfortran -c f_rand_M.f90
echo "building & executing fortran main"
gfortran f_main.f90 f_rand_M.o c_rand.o cxx11_rand.o -lstdc++ -o f_main.exe
./f_main.exe
你的输出应该是这样的(当然有不同的随机数 - 这里的种子是从“熵源”中选择的,例如墙上的时间)。
compiling objects
building & executing fortran main
0.47439556226575341
0.11177335018127127
0.10417488557661241
0.77378163596792404
0.20780793755332663
0.27951447624366532
0.66920698086955666
0.80676663600103105
0.98028384008440417
0.88893587108730432
我在Mac上使用GCC 4.9进行测试。
答案 2 :(得分:1)
使用的特定随机数生成器取决于编译器。也许记录在案,也许不是。也许会有所变化。对于高质量的工作,我会使用其他地方的库/源代码。使用Mersenne Twister的Fortran实现的网页:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/fortran.html。我使用了http://theo.phys.sci.hiroshima-u.ac.jp/~ishikawa/PRNG/mt_stream_en.html并对原始实现进行了验证。此版本对多线程程序很有用。
答案 3 :(得分:0)
当您使用MC时,PRNG是一个不好的选择,并且无论使用哪种编程语言都无关紧要。对于MC模拟,使用Random ORG或hardware random number generator等服务始终是个好主意。第47项中的书Effective Java清楚地显示了有问题的PRNG的一个例子。对于PRNG,您永远不能确定您的内部实施是否正常。