Can Random Number Generator of Fortran 90 be trusted for Monte Carlo Integration?

寵の児 提交于 2019-12-18 15:48:45

问题


I have written a short monte carlo integration algorithm to calculate an integral in Fortran 90. I once compared the result obtained by solving the integral with respect to some parameter using the intrinsic random number generator with the random number generator method ran1 presented in Numerical Recipes for Fortran90 Volume 2.

Running the same algorithm twice, once calling the intrinsic random_seed(), then always call random_number() and once calling the ran1() method provided in the Numerical Recipe book I obtain as result in principal the same shape but the intrinsic result is a continuous curve in contrast to the ran1 result. In both cases I call the function with random parameters 10,000 times for a parameter value q, add it and then go on to the next q value and call the function 10,000 times etc.

A comparative image of the result can be found here:

If I increase the number of calls both curves converge. But I was wondering: why does the intrinsic random number generator generate this smoothness? Is it still generally advised to use it or are there are other more advised RNG? I suppose the continuous result is a result of the "less" randomness of the intrinsic number generator.

(I left out the source code as I don't think that there is a lot of input from it. If somebody cares I can hand it in later.)


回答1:


There are NO guarantees about the quality of the pseudo random generator in standard Fortran. If you care about some particular quality of implementation for cryptography or science sensitive to random numbers (Monte-Carlo), you should use some library which you have control about.

You can study the manual of your compiler to find out what it says about the random number generator, but every compiler can implement a completely different algorithm to generate random numbers.

Numerical Recipes is actually not well received by some people in the numerical mathematics community http://www.uwyo.edu/buerkle/misc/wnotnr.html

This site is not for software recommendation, but this article (link given by roygvib in a comment): https://arxiv.org/abs/1005.4117 is a good review with examples of bad and good algorithms, methods how to test them, how to generate arbitrary number distributions and examples of calls of two example libraries in C (one of them can be called from Fortran as well).

Personally I use this https://bitbucket.org/LadaF/elmm/src/e732cb9bee3352877d09ae7f6b6722157a819f2c/src/rng_par_zig.f90?at=master parallel PRNG, but I didn't test the quality, I personally just need speed. But this is not a software recommendation site.




回答2:


I agree with Vladamir F. But...

To help you in your quest for better random numbers, consider the fairly recent addition to C++, C++11 Pseudo Random Number Generators. Mersenne twister and lots of others are there. It's a pretty well-thought out system. I see two ways you could test those sequences:

  • make a system call from Fortran to a little C++ utility that generates a bunch of them for you or
  • bind the random number generators to Fortran through ISO_C_BINDING.

I prefer the second and because the bindings are a little tricky, I have prepared an example. The files are:

  1. cxx11_rand.h and cxx11_rand.cpp which define calls to the random number generator
  2. c_rand.cpp which calls the C++ functions in C functions
  3. f_rand_M.f90 which binds the C functions to Fortran
  4. f_main.f90 which uses the module functions to generate 10 random numbers in [0,1).

cxx11_rand.h

#ifndef CXX11_RAND_H
#define CXX11_RAND_H

void cxx11_init();
double cxx11_rand();

#endif

cxx11_rand.cpp

#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 );
}

c_rand.cpp

#include "cxx11_rand.h"

#ifdef __cplusplus
extern "C" {
#endif

void c_init(){
    cxx11_init();
}

double c_rand(){
    return cxx11_rand();
}

#ifdef __cplusplus
}
#endif

f_rand_M.f90

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

f_main.f90

program main

    use f_rand_M

    implicit none
    integer :: i

    call f_init()
    do i=1,10
        write(*,*)f_rand()
    end do

end program

You can compile/link with the following GNU commands

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

Your output should look like this (with different random numbers of course--the seed here was chosen from a "source of entropy", e.g. wall time).

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

I used GCC 4.9 on a Mac for testing.




回答3:


The particular random number generator used depends on the compiler. Perhaps documented, perhaps not. Perhaps subject to change. For high quality work, I would use library / source code from elsewhere. A webpage with Fortran implementations of the Mersenne Twister: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/FORTRAN/fortran.html. I have used http://theo.phys.sci.hiroshima-u.ac.jp/~ishikawa/PRNG/mt_stream_en.html and verified against the original implementation. This version is useful for multi-threaded programs.




回答4:


PRNG is a bad option when you are doing MC and it does not matter in which programming language. For MC simulations it is always good idea to use service like Random ORG or hardware random number generator. The book Effective Java, in Item 47, clearly shows an example of problematic PRNG. With PRNGs you are never sure that you are OK with their internal implementation.



来源:https://stackoverflow.com/questions/38262846/can-random-number-generator-of-fortran-90-be-trusted-for-monte-carlo-integration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!