Ich habe mit der Mersenne Twister-Implementierung der gcc C++ - Standardbibliothek getestet. Es übertrifft sowohl den linearen Kongruenzgenerator als auch die C rand
, die höchstwahrscheinlich eine LCG ist. A boost documentation scheint auch ein ähnliches Ergebnis zu geben, aber Mersenne twister noch mehr zu bevorzugen. Kann das jemand erklären? Warum ist Mersenne schneller als der lineare Kongruenzgenerator?
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <random>
class Timer
{
private:
std::chrono::high_resolution_clock::time_point start_time;
std::chrono::high_resolution_clock::time_point stop_time;
public:
void start()
{
start_time = std::chrono::high_resolution_clock::now();
}
void stop()
{
stop_time = std::chrono::high_resolution_clock::now();
}
double measure()
{
using namespace std::chrono;
return duration_cast<microseconds>
(stop_time - start_time).count()/1000000.0;
}
};
template<typename T>
class Random
{
private:
T generator;
public:
Random()
: generator
(std::chrono::high_resolution_clock::now().time_since_epoch().count())
{
}
int generate_integer(int begin, int end)
{
return std::uniform_int_distribution<int>(begin, end - 1)(generator);
}
};
int main()
{
constexpr int n = 300000000;
Random<std::minstd_rand> mr;
Random<std::mt19937> mt;
Timer t;
for (int j = 0; j < 3; ++j)
{
t.start();
for (int i = 0; i < n; ++i)
{
static_cast<volatile void>(mr.generate_integer(0, 10));
}
t.stop();
std::cout << "minstd " << t.measure() << std::endl;
t.start();
for (int i = 0; i < n; ++i)
{
static_cast<volatile void>(mt.generate_integer(0, 10));
}
t.stop();
std::cout << "mersenne " << t.measure() << std::endl;
t.start();
for (int i = 0; i < n; ++i)
{
static_cast<volatile void>(std::rand() % 10);
}
t.stop();
std::cout << "rand " << t.measure() << std::endl;
}
}
Ergebnis
minstd 4.70876
mersenne 1.55853
rand 4.11873
minstd 4.53199
mersenne 1.55928
rand 4.15159
minstd 4.5374
mersenne 1.55667
rand 4.13715
Haben Sie ein anderes Ergebnis erwartet? – emlai
@zenith Sicher, eine LCG ist nur ein paar arithmetische Operationen, während mt19937 mehrere Seiten Code enthält. – xiver77
Haben Sie Optimierungen aktiviert? Für gute Ergebnisse sollten Sie volle Optimierungen einschalten und einen Nebeneffekt (Akkumulieren einer Prüfsumme?) Der zeitgesteuerten Aktivität erzwingen, wie das Ausdrucken eines Prüfsummenergebnisses * nachdem der Timer gestoppt wurde, um zu verhindern, dass der Compiler die zeitgesteuerte Aktivität weg optimiert. – Galik