Je voudrais générer un grand nombre, n
, (c'est-à-dire n >= 1,000,000,000
) des nombres aléatoires triés et uniformément distribués en C++.
A d'abord et une approche simple que j'ai considérée était de
n
nombres uniformément distribués à l'aide d'un std::uniform_real_distribution<double>
,std::sort
.Cependant, cela prend plusieurs minutes.
A Deuxièmement et une approche plus sophistiquée consistait à faire paralléliser les deux étapes comme dans:
template <typename T>
void computeUniformDistribution(std::vector<T>& elements)
{
#pragma omp parallel
{
std::seed_seq seed{distribution_seed, static_cast<size_t>(omp_get_thread_num())};
std::mt19937 prng = std::mt19937(seed);
std::uniform_real_distribution<double> uniform_dist(0, std::numeric_limits<T>::max());
#pragma omp for
for (size_t i = 0; i < elements.size(); ++i)
{
elements[i] = static_cast<T>(uniform_dist(prng));
}
}
std::sort(std::execution::par_unseq, elements.begin(), elements.end());
}
Cependant, même cela prend environ 30 secondes. Étant donné que la génération des nombres uniformément distribués prend uniquement environ 1.5 secondes, le goulot d'étranglement reste la phase de tri.
Par conséquent, j'aimerais poser la question suivante: Comment puis-je générer efficacement des données uniformément distribuées de manière triée?
Il existe une simple observation impliquant des nombres aléatoires uniformes triés dans [0, 1]:
Ainsi, chaque numéro peut être généré un bit à la fois, de gauche à droite après le point binaire. Voici un croquis de la manière dont cela fonctionne pour générer N Tri des nombres aléatoires uniformes:
À ce stade, nous avons une liste triée de nombres aléatoires avec des comptes de bits variés. Tout ce qui reste à faire est de remplir chaque nombre avec des bits aléatoires uniformes au besoin (ou de couper les bits d'excès ronds) pour donner le numéro P bits (par exemple 53 bits pour la double précision) . Ensuite, divisez chaque numéro par 2 P.
Je donne un algorithme similaire Pour trouver le k - Le plus petit de N Numéros aléatoires.