////// This test program requires at least C++11: // g++ or icc: -std=c++11 or -std=c++14 // g++ 4.x: -std=c++0x #include #include #include #include #include #include #include #include #include #include #include #include #include "xoroshiro128_plus.h" using namespace xoroshiro128_plus ; int main() { // Simple test program for the xoroshiro128+ RNG // Define a seed. uint64_t seed[2] ; // Get some seed values from hardware if available using C++11 Xoroshiro128_plus::get_random_seed(seed) ; // Make an RNG from the array Xoroshiro128_plus rng1(seed) ; // Make a vector then do it again std::vector vseed ; vseed.push_back(seed[0]) ; vseed.push_back(seed[1]) ; Xoroshiro128_plus rng2(vseed.begin(),vseed.end()) ; const int NUM = 10 ; // Print out a few 64-bit ints. std::cout <<"2 RNGs with different constructors produce the same numbers: " << std::endl; for (int i = 0 ; i < NUM ; ++i) { std::cout << rng1.next_uint64() << " : " << rng2.next_uint64() << std::endl ; } // And now some doubles. std::cout << std::endl << "Some doubles: " << std::endl ; std::cout.precision(std::numeric_limits< double >::max_digits10); for (int i = 0 ; i < NUM ; ++i) { std::cout << std::fixed << rng2.next_double() << std::endl ; } // And now some floats. std::cout << std::endl << "Some floats starting from the same point, should be the same as the doubles: " << std::endl ; std::cout.precision(std::numeric_limits< float >::max_digits10); for (int i = 0 ; i < NUM ; ++i) { std::cout << std::fixed << rng1.next_float() << std::endl ; } std::cout.precision(std::numeric_limits< double >::max_digits10); // Now jump auto rng3 = rng2.jump(); // And printout a few more ... std::cout << std::endl << "Seed and jump seed output" << std::endl ; for (int i = 0 ; i < NUM ; ++i) { std::cout << rng2.next_uint64() << " : " << rng3.next_uint64() << std::endl ; } // Now for a benchmark. Time to generate 1 billion doubles. std::cout << std::endl << "Timing the generation of 1 billion doubles. " << std::endl ; const long COUNT = 1000000000 ; std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); double x ; for (long i = 0 ; i < COUNT ; ++i) { x = rng3.next_double() ; } std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now(); std::cout << "Nanosec per double = " << std::chrono::duration_cast(end - begin).count() / static_cast(COUNT) ; std::cout << std::endl; // Now compare with time to generate using Mersenne Twister auto mtseed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); std::mt19937_64 mtrand(mtseed); std::uniform_real_distribution double_dist(0.0, 1.0); std::cout << std::endl << "Timing the generation of 1 billion doubles using Mersenne Twister. " << std::endl ; begin = std::chrono::steady_clock::now(); for (long i = 0 ; i < COUNT ; ++i) { x = double_dist( mtrand) ; } end= std::chrono::steady_clock::now(); std::cout << "Nanosec per double (MT) = " << std::chrono::duration_cast(end - begin).count() / static_cast(COUNT) ; std::cout << std::endl; // print the last value of x to make sure compiler doesn't optimize // away the M-T loop! std::cout << x << std::endl ; return 0 ; }