Si la précision est un problème ici, vous pouvez créer des nombres aléatoires avec une graduation plus fine en randomisant les bits significatifs. Supposons que nous voulions avoir un double entre 0,0 et 1000,0.
Sur MSVC (12 / Win32) RAND_MAX est 32767 par exemple.
Si vous utilisez la méthode commune rand()/RAND_MAX
schéma vos écarts seront aussi grands que
1.0 / 32767.0 * ( 1000.0 - 0.0) = 0.0305 ...
Dans le cas des variables doubles IEE 754 (53 bits significatifs) et de la randomisation sur 53 bits, le plus petit écart de randomisation possible pour le problème 0 à 1000 sera de
2^-53 * (1000.0 - 0.0) = 1.110e-13
et donc nettement plus faible.
L'inconvénient est que 4 appels à rand() seront nécessaires pour obtenir le nombre intégral randomisé (en supposant un RNG de 15 bits).
double random_range (double const range_min, double const range_max)
{
static unsigned long long const mant_mask53(9007199254740991);
static double const i_to_d53(1.0/9007199254740992.0);
unsigned long long const r( (unsigned long long(rand()) | (unsigned long long(rand()) << 15) | (unsigned long long(rand()) << 30) | (unsigned long long(rand()) << 45)) & mant_mask53 );
return range_min + i_to_d53*double(r)*(range_max-range_min);
}
Si le nombre de bits pour la mantisse ou le RNG est inconnu, les valeurs respectives doivent être obtenues dans la fonction.
#include <limits>
using namespace std;
double random_range_p (double const range_min, double const range_max)
{
static unsigned long long const num_mant_bits(numeric_limits<double>::digits), ll_one(1),
mant_limit(ll_one << num_mant_bits);
static double const i_to_d(1.0/double(mant_limit));
static size_t num_rand_calls, rng_bits;
if (num_rand_calls == 0 || rng_bits == 0)
{
size_t const rand_max(RAND_MAX), one(1);
while (rand_max > (one << rng_bits))
{
++rng_bits;
}
num_rand_calls = size_t(ceil(double(num_mant_bits)/double(rng_bits)));
}
unsigned long long r(0);
for (size_t i=0; i<num_rand_calls; ++i)
{
r |= (unsigned long long(rand()) << (i*rng_bits));
}
r = r & (mant_limit-ll_one);
return range_min + i_to_d*double(r)*(range_max-range_min);
}
Note : Je ne sais pas si le nombre de bits pour les longs non signés (64 bits) est supérieur au nombre de bits de la double mantisse (53 bits pour IEE 754) sur toutes les plateformes ou non. Il serait probablement "intelligent" d'inclure une vérification du type if (sizeof(unsigned long long)*8 > num_mant_bits) ...
si ce n'est pas le cas.
6 votes
"ces numéros devraient ressembler à xxxxx,yyyyy". La façon de générer des doubles aléatoires et la façon de formater les doubles en tant que chaînes de caractères sont des questions complètement distinctes.
0 votes
Et en y réfléchissant bien, on peut aussi envisager de générer une distribution uniforme doubles et en générant des données uniformément réparties décimales sont des tâches quelque peu différentes, bien que liées.
0 votes
La génération de nombres entiers uniformément distribués est plus étroitement liée au problème des décimales.