Random Engine Differences

前端 未结 7 1407
灰色年华
灰色年华 2020-12-13 02:06

The C++11 standard specifies a number of different engines for random number generation: linear_congruential_engine, mersenne_twister_engine,

7条回答
  •  青春惊慌失措
    2020-12-13 02:24

    I just saw this answer from Marnos and decided to test it myself. I used std::chono::high_resolution_clock to time 100000 samples 100 times to produce an average. I measured everything in std::chrono::nanoseconds and ended up with different results:

    std::minstd_rand had an average of 28991658 nanoseconds

    std::mt19937 had an average of 29871710 nanoseconds

    ranlux48_base had an average of 29281677 nanoseconds

    This is on a Windows 7 machine. Compiler is Mingw-Builds 4.8.1 64bit. This is obviously using the C++11 flag and no optimisation flags.

    When I turn on -O3 optimisations, the std::minstd_rand and ranlux48_base actually run faster than what the implementation of high_precision_clock can measure; however std::mt19937 still takes 730045 nanoseconds, or 3/4 of a second.

    So, as he said, it's implementation specific, but at least in GCC the average time seems to stick to what the descriptions in the accepted answer say. Mersenne Twister seems to benefit the least from optimizations, whereas the other two really just throw out the random numbers unbelieveably fast once you factor in compiler optimizations.

    As an aside, I'd been using Mersenne Twister engine in my noise generation library (it doesn't precompute gradients), so I think I'll switch to one of the others to really see some speed improvements. In my case, the "true" randomness doesn't matter.

    Code:

    #include 
    #include 
    #include 
    
    using namespace std;
    using namespace std::chrono;
    
    int main()
    {
        minstd_rand linearCongruentialEngine;
        mt19937 mersenneTwister;
        ranlux48_base subtractWithCarry;
        uniform_real_distribution distro;
    
        int numSamples = 100000;
        int repeats = 100;
    
        long long int avgL = 0;
        long long int avgM = 0;
        long long int avgS = 0;
    
        cout << "results:" << endl;
    
        for(int j = 0; j < repeats; ++j)
        {
            cout << "start of sequence: " << j << endl;
    
            auto start = high_resolution_clock::now();
            for(int i = 0; i < numSamples; ++i)
                distro(linearCongruentialEngine);
            auto stop = high_resolution_clock::now();
            auto L = duration_cast(stop-start).count();
            avgL += L;
            cout << "Linear Congruential:\t" << L << endl;
    
            start = high_resolution_clock::now();
            for(int i = 0; i < numSamples; ++i)
                distro(mersenneTwister);
            stop = high_resolution_clock::now();
            auto M = duration_cast(stop-start).count();
            avgM += M;
            cout << "Mersenne Twister:\t" << M << endl;
    
            start = high_resolution_clock::now();
            for(int i = 0; i < numSamples; ++i)
                distro(subtractWithCarry);
            stop = high_resolution_clock::now();
            auto S = duration_cast(stop-start).count();
            avgS += S;
            cout << "Subtract With Carry:\t" << S << endl;
        }
    
        cout << setprecision(10) << "\naverage:\nLinear Congruential: " << (long double)(avgL/repeats)
        << "\nMersenne Twister: " << (long double)(avgM/repeats)
        << "\nSubtract with Carry: " << (long double)(avgS/repeats) << endl;
    }
    

提交回复
热议问题