I have a question similar to this.
To summarize ,
I want to a random number generated in a function call, in the range [0 maxVal]
. The upper bound (maxVal
) is different everytime function is called. I tried to test the performance of the code in the answer and my own way to generate a random number (with a wrapper around std::mt19937
)
According to my performance tests, using a uniform_int_distribution object in the function gives me inferior performance.
Here is my code
#include <iostream>
#include <random>
#include <cassert>
#include <chrono>
#include <thread>
class CustomMtRand
{
private:
std::mt19937 mtRandEngine;
public:
CustomMtRand(int seed) :mtRandEngine(seed) {}
//range [0, maxVal - 1]
unsigned int randomInt(unsigned int maxVal)
{
assert(maxVal != 0); //do not pass in 0 as maxVal.
auto randVal = mtRandEngine(); // generates in range [0 4294967295]
double scaling = (randVal / 4294967296.0);
unsigned int retVal = std::floor(maxVal * scaling);
return retVal;
}
};
int main()
{
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
CustomMtRand customMtRand(0);
constexpr int numTests = 5;
duration<double, std::milli> sumCustom(0);
duration<double, std::milli> sumMtRand(0);
for (int j = 0; j < numTests; j++)
{
constexpr long numTestIters = 0xffffff;
auto t1 = high_resolution_clock::now();
for (auto i = 0; i < numTestIters; i++)
{
auto rand = 1 + std::rand() % 10;
customMtRand.randomInt(rand);
}
auto t2 = high_resolution_clock::now();
duration<double, std::milli> execTime = t2 - t1;
std::cout << "Custom Rand :" << execTime.count() << " ms\n";
sumCustom += execTime;
std::mt19937 mtRandEngine;
t1 = high_resolution_clock::now();
for (auto i = 0; i < numTestIters; i++)
{
unsigned int rand = 1 + std::rand() % 10;
std::uniform_int_distribution<unsigned int>{0, rand}(mtRandEngine);
}
t2 = high_resolution_clock::now();
execTime = t2 - t1;
std::cout << "MT Rand :" << execTime.count() << " ms\n";
sumMtRand += execTime;
}
std::cout << "--------------------------------\n";
std::cout << "Custom Rand Average :" << (sumCustom.count() / numTests) << " ms\n";
std::cout << "MT Rand Average :" << (sumMtRand.count() / numTests) << " ms\n";
return 0;
}
Here is an example result
Custom Rand :216.012 ms
MT Rand :297.231 ms
Custom Rand :217.576 ms
MT Rand :315.173 ms
Custom Rand :216.519 ms
MT Rand :324.193 ms
Custom Rand :214.586 ms
MT Rand :302.604 ms
Custom Rand :213.5 ms
MT Rand :296.29 ms
--------------------------------
Custom Rand Average :215.639 ms
MT Rand Average :307.098 ms
I have two questions.
- Is the way I am testing this correct?
- If this is correct, is there an alternative to writing a wrapper?
EDIT: I ran the code on quick-bench.com. Here is what I tried
static void cRandCall(benchmark::State& state) {
// Code before the loop is not measured
CustomMtRand customMtRand(0);
for (auto _ : state) {
unsigned int rand = 1 + std::rand() % 10;
int result = customMtRand.randomInt(rand);
benchmark::DoNotOptimize(result);
}
}
BENCHMARK(cRandCall);
static void mtRandCall(benchmark::State& state) {
// Code before the loop is not measured
std::mt19937 mtRandEngine;
for (auto _ : state) {
unsigned int rand = 1 + std::rand() % 10;
int result = std::uniform_int_distribution<unsigned int>{0, rand}(mtRandEngine);
benchmark::DoNotOptimize(result);
}
}
BENCHMARK(mtRandCall);
My code still appears to be little bit faster.