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

前端 未结 4 1632
悲哀的现实
悲哀的现实 2021-01-02 07:28

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

相关标签:
4条回答
  • 2021-01-02 07:31

    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.

    0 讨论(0)
  • 2021-01-02 07:34

    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.

    0 讨论(0)
  • 2021-01-02 07:40

    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/master/src/rng_par_zig.f90 parallel PRNG, but I didn't test the quality, I personally just need speed. But this is not a software recommendation site.

    0 讨论(0)
  • 2021-01-02 07:42

    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.

    0 讨论(0)
提交回复
热议问题