Q: Как я могу генерировать (много) равномерно распределенные целые числа из априорных неизвестных диапазонов? Каков предпочтительный способ с точки зрения производительности (миллионы сгенерированных чисел)?
Контекст: в моем приложении мне нужно генерировать много псевдослучайных чисел во многих местах. Я использую шаблон синглтона для генератора, чтобы поддерживать воспроизводимость запуска приложения. В моем случае распределение всегда одинаково, но проблема в том, что существует слишком много возможных диапазонов, чтобы предварительно создать объект распределения в стиле C ++ 11.
То, что я попробовал: есть два очевидных решения для этого, во-первых, это иметь одноразовые объекты распределения, а во-вторых, использовать по модулю для преобразования случайного числа из максимально широкого диапазона в желаемое. Но почему-то я сомневаюсь, что это лучше всего 🙂
#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();
}
я бы сделал
int getIntFromRange1(int from, int to){
std::uniform_int_distribution<int> dist(from, to);
return dist(mt);
}
Я бы сделал как в Jarod42 ответ: объекты распределения должны быть легкими, поэтому создание нового распределения, когда вам нужно случайное число, является простым и быстрым (случайный движок стоит дорого).
Однако вы также можете рассмотреть эту реализацию:
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));
}
Смысл в том, что могут быть дистрибутивы, которые должны хранить значения / состояния.
Это, вероятно, не относится к целым числам и равномерному распределению, но интересно, что в N4316 — STD :: RAND замена предлагаемая реализация использует эту технику.