C++11 Generating random numbers from frequently ch

2019-02-22 03:17发布

Q: How do I generate (many) uniformly distributed integers from a-priory unknown ranges? What is the prefered way in terms of performance (milions of generated numbers)?

Context: In my app I have to generate many pseudo random numbers in many places. I use singleton pattern for the generator to maintain reproducibility of the app's run. Distribution is always uniform in my case, but the problem is that there are far too many possible ranges to pre-made the distribution object in C++11 style.

What I tried: There are two obvious solutions to this, first is to have one-time distribution objects and second is to use modulo to transform random number from widest possible range to the desired one. But somehow i doubt these are best possible :)

#include <random>
#include <iostream>
#include "limits.h"
using namespace std;

mt19937 mt;
uniform_int_distribution<int> * fixedDist;
uniform_int_distribution<int> * variableDist;

// this version creates and delete dist after just one use
int getIntFromRange1(int from, int to){
    variableDist = new uniform_int_distribution<int>(from,to);
    int num = (*variableDist)(mt);
    delete variableDist;
    return num;
}

// this version contains modulo
int getIntFromRange2(int from, int to){
    int num = (*fixedDist)(mt);
    int diff = to - from;
    num = num % diff;
    return num + from;
}

int main(){ 
   mt.seed(123456);
   fixedDist= new uniform_int_distribution<int>(0,INT_MAX)

   int a = getIntFromRange1(1,10); // 1 and 10 are just for illustration
   int b = getIntFromRange2(1,10); // can change freely

   cout << "a: " << a << endl; // a: 6
   cout << "b: " << b << endl; // b: 9

   getchar();
}

Duplicate question

Vary range of uniform_int_distribution

2条回答
神经病院院长
2楼-- · 2019-02-22 03:52

I would do as in Jarod42's answer: distribution objects should be lightweight, so constructing a new distribution when you need a random number is simple and fast (it's the random engine that is expensive).

However you can also consider this implementation:

inline int get_int_from_range(int from, int to)
{
  using distribution_type = std::uniform_int_distribution<int>;
  using param_type = typename distribution_type::param_type;

  thread_local distribution_type dist;
  return dist(mt, param_type(from, to));
}

The rationale is that there could be distributions that need to store values/states.

This isn't probably the case for integers and uniform distribution, but it's interesting that in N4316 - std::rand replacement the proposed implementation uses this technique.

查看更多
做自己的国王
3楼-- · 2019-02-22 03:59

I would do

int getIntFromRange1(int from, int to){
    std::uniform_int_distribution<int> dist(from, to);
    return dist(mt);
}
查看更多
登录 后发表回答