Génération aléatoire de nombres flottants

271

Comment générer des flottants aléatoires en C ++?

Je pensais que je pouvais prendre le rand entier et le diviser par quelque chose, serait-ce suffisant?

hasen
la source
2
Cela dépend plutôt de la raison pour laquelle vous voulez le nombre et de la façon aléatoire. typiquement rand () donnera 15 bits de caractère aléatoire, mais les flottants ont une précision de 23 bits, il manquera donc certaines valeurs.
Pete Kirkham
1
J'ai mis à jour ma réponse pour inclure toutes les principales options disponibles et mon choix de me concentrer sur l'en- randomtête ajouté en C ++ 11 est encore renforcé par le document standard N3924: Décourager rand () en C ++ 14 . J'inclus rand()dans ma réponse pour des considérations principalement historiques, mais aussi pour réaliser que les anciennes applications existent.
Shafik Yaghmour
Ma réponse comprend comment éviter d'obtenir les mêmes numéros à chaque fois avec l'en- <random>tête
Andreas DM

Réponses:

381

rand()peut être utilisé pour générer des nombres pseudo-aléatoires en C ++. En combinaison avec RAND_MAXet un peu de mathématiques, vous pouvez générer des nombres aléatoires dans n'importe quel intervalle arbitraire que vous choisissez. Ceci est suffisant pour des fins d'apprentissage et des programmes de jouets. Si vous avez besoin de nombres vraiment aléatoires avec une distribution normale, vous devrez utiliser une méthode plus avancée.


Cela générera un nombre compris entre 0,0 et 1,0, inclus.

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

Cela va générer un certain nombre de 0,0 à un certain arbitraire float, X:

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));

Cela générera un nombre de certains arbitraires LOà certains arbitraires HI:

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));

Notez que la rand()fonction ne sera souvent pas suffisante si vous avez besoin de nombres vraiment aléatoires.


Avant d'appeler rand(), vous devez d'abord "amorcer" le générateur de nombres aléatoires en appelant srand(). Cela devrait être fait une fois pendant l'exécution de votre programme - pas une fois à chaque appel rand(). Cela se fait souvent comme ceci:

srand (static_cast <unsigned> (time(0)));

Pour appeler randou srandvous devez #include <cstdlib>.

Pour appeler time, vous devez #include <ctime>.

John Dibling
la source
22
N'oubliez pas de semer en premier!
Klaim
14
Mieux vaut noter que les deux limites sont inclusives.
dmckee --- chaton ex-modérateur
14
Cette réponse est trompeuse. Il a été couvert à Going Native 2013 la semaine dernière; rand () Considéré nuisible, channel9.msdn.com/Events/GoingNative/2013/… pour une explication très détaillée.
Ade Miller
14
Je ne comprends pas pourquoi tant de gens ont voté pour cette réponse. C'est mathématiquement incorrect. RAND_MAX est un très petit nombre (généralement 2 ^ 16). Cela signifie qu'à partir de 23 bits de la virgule flottante, vous ne faites que 15 au hasard. Les autres seront probablement nuls. Vous obtiendrez en effet des nombres aléatoires en distribution uniforme mais de faible précision. Par exemple, votre générateur aléatoire peut générer 0,00001 et 0,00002 mais ne peut pas générer 0,000017. Vous avez donc une distribution uniforme mais de faible précision (256 fois moins de précision que la virgule flottante réelle).
DanielHsH
10
@DanielHsH: L'OP a spécifiquement demandé quelle mécanique pouvait être utilisée pour générer des flottants aléatoires avec rand(). Cette question, et ma réponse, était spécifiquement axée sur l'apprentissage des bases et n'était pas préoccupée par un degré élevé de précision. Vous devez apprendre à marcher avant de pouvoir courir.
John Dibling
137

C ++ 11 vous offre de nombreuses nouvelles options avec random. L'article canonique sur ce sujet serait N3551, Génération de nombres aléatoires en C ++ 11

Pour voir pourquoi l'utilisation rand()peut être problématique, voir le matériel de présentation rand () Considered Harmful de Stephan T. Lavavej donné lors de l' événement GoingNative 2013 . Les diapositives sont dans les commentaires mais voici un lien direct .

Je couvre également boostainsi que l'utilisation randcar le code hérité peut encore nécessiter son support.

L'exemple ci-dessous est distillé à partir du site cppreference et utilise le moteur std :: mersenne_twister_engine et le std :: uniform_real_distribution qui génère des nombres dans l' [0,10)intervalle, avec d'autres moteurs et distributions commentés ( voir en direct ):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    //
    // Engines 
    //
    std::mt19937 e2(rd());
    //std::knuth_b e2(rd());
    //std::default_random_engine e2(rd()) ;

    //
    // Distribtuions
    //
    std::uniform_real_distribution<> dist(0, 10);
    //std::normal_distribution<> dist(2, 2);
    //std::student_t_distribution<> dist(5);
    //std::poisson_distribution<> dist(2);
    //std::extreme_value_distribution<> dist(0,2);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

la sortie sera similaire à la suivante:

0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****

La sortie variera en fonction de la distribution que vous choisissez, donc si nous décidions d'aller avec std :: normal_distribution avec une valeur 2à la fois pour la moyenne et stddev, par exemple, dist(2, 2)la sortie serait similaire à ceci ( voir en direct ):

-6 
-5 
-4 
-3 
-2 **
-1 ****
 0 *******
 1 *********
 2 *********
 3 *******
 4 ****
 5 **
 6 
 7 
 8 
 9 

Ce qui suit est une version modifiée d'une partie du code présenté dans N3551( voir en direct ):

#include <algorithm>
#include <array>
#include <iostream>
#include <random>

std::default_random_engine & global_urng( )
{
    static std::default_random_engine u{};
    return u ;
}

void randomize( )
{
    static std::random_device rd{};
    global_urng().seed( rd() );
}

int main( )
{
  // Manufacture a deck of cards:
  using card = int;
  std::array<card,52> deck{};
  std::iota(deck.begin(), deck.end(), 0);

  randomize( ) ;  

  std::shuffle(deck.begin(), deck.end(), global_urng());
  // Display each card in the shuffled deck:
  auto suit = []( card c ) { return "SHDC"[c / 13]; };
  auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };

  for( card c : deck )
      std::cout << ' ' << rank(c) << suit(c);

   std::cout << std::endl;
}

Les résultats ressembleront à:

5H 5S COMME 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7S 6S

Renforcer

Bien sûr, Boost.Random est toujours une option également, ici j'utilise boost :: random :: uniform_real_distribution :

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

int main()
{
    boost::random::mt19937 gen;
    boost::random::uniform_real_distribution<> dist(0, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::floor(dist(gen))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

rand()

Si vous devez utiliser rand()alors nous pouvons aller à la FAQ C pour un guide sur Comment puis-je générer des nombres aléatoires à virgule flottante? , qui donne essentiellement un exemple similaire à celui-ci pour générer un sur l'intervalle [0,1):

#include <stdlib.h>

double randZeroToOne()
{
    return rand() / (RAND_MAX + 1.);
}

et pour générer un nombre aléatoire dans la plage de [M,N):

double randMToN(double M, double N)
{
    return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
}
Shafik Yaghmour
la source
1
pouvez-vous réparer vos randMToNpls? soit noter que c'est [M,N]ou ajouter à + 1.partir de ce qui précède randZeroToOne. -> pensez à l'appeler comme ceci:randMToN(0.0, 1.0);
BeyelerStudios
1
Faites également attention à la division par zéro à (N-M). Une bonne façon de traiter cette erreur se trouve ici: stackoverflow.com/questions/33058848/…
Dr Beco
61

Jetez un oeil à Boost.Random . Vous pouvez faire quelque chose comme ça:

float gen_random_float(float min, float max)
{
    boost::mt19937 rng;
    boost::uniform_real<float> u(min, max);
    boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
    return gen();
}

Jouez, vous feriez mieux de passer le même objet mt19937 autour au lieu d'en construire un nouveau à chaque fois, mais j'espère que vous aurez l'idée.

rlbond
la source
1
uniform_real utilise un intervalle semi-ouvert [min, max), ce qui signifie que vous obtiendrez votre valeur minimale mais n'atteindrez jamais la valeur maximale. C'est quelque chose à considérer, bien que si vous arrondissez d'une manière ou d'une autre, vous pouvez surmonter ce problème.
TehWan
20
Cela fait maintenant partie de C ++ 11.
Tomas Andrle
@Wolf dans les applications pratiques, les chances de toucher une valeur en virgule flottante spécifique sont si faibles qu'il importe peu que le point final soit inclus ou exclu. Si vous avez besoin , maxmais peut utiliser une composition non limitée min, vous pouvez inverser facilement l'intervalle: return min + max - gen();.
Mark Ransom
26

Dans la version moderne, c++vous pouvez utiliser l'en- <random>tête fourni avec c++11.
Pour obtenir des statistiques aléatoires float, vous pouvez les utiliser std::uniform_real_distribution<>.

Vous pouvez utiliser une fonction pour générer les nombres et si vous ne voulez pas que les nombres soient toujours les mêmes , définissez le moteur et la distribution static.
Exemple:

float get_random()
{
    static std::default_random_engine e;
    static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
    return dis(e);
}

Il est idéal de placer le floats dans un conteneur tel que std::vector:

int main()
{
    std::vector<float> nums;
    for (int i{}; i != 5; ++i) // Generate 5 random floats
        nums.emplace_back(get_random());

    for (const auto& i : nums) std::cout << i << " ";
}

Exemple de sortie:

0.0518757 0.969106 0.0985112 0.0895674 0.895542
Andreas DM
la source
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1est techniquement incorrect, 1.0 ne sera jamais généré, voir en.cppreference.com/w/cpp/numeric/random/… To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
Troyseph
1
Cela devrait être la réponse acceptée, c'est flippant 2020.
Alex
25

Appelez le code avec deux floatvaleurs, le code fonctionne dans n'importe quelle plage.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
Ivan Prodanov
la source
Il peut être utile de mentionner qu'il s'agit d'un cas d'utilisation potentiel pour fmaf()(ou la fma()surcharge flottante en C ++) en C99 ou C ++ 11, qui pourrait conserver plus de précision. Comme dans fmaf((float)rand() / RAND_MAX, b - a, a),.
Tim Čas
22

Si vous utilisez C ++ et non C, souvenez-vous que dans le rapport technique 1 (TR1) et dans le projet C ++ 0x, ils ont ajouté des fonctionnalités pour un générateur de nombres aléatoires dans le fichier d'en-tête, je pense qu'il est identique au Boost. Bibliothèque aléatoire et certainement plus flexible et "moderne" que la fonction de bibliothèque C, rand.

Cette syntaxe offre la possibilité de choisir un générateur (comme le mersenne twister mt19937) puis de choisir une distribution (normal, bernoulli, binomial etc.).

La syntaxe est la suivante (sans vergogne emprunté à ce site ):

  #include <iostream>
  #include <random>

  ...

  std::tr1::mt19937 eng;  // a core engine class 
  std::tr1::normal_distribution<float> dist;     

  for (int i = 0; i < 10; ++i)        
      std::cout << dist(eng) << std::endl;
Meule
la source
2
C'est maintenant en C ++ 11, dist peut également être initialisé avec des valeurs min et max.
Étienne
Il me semble étrange de mettre le min et le max dans l'initialiseur et de fournir le générateur lors de l'obtention d'une valeur - je préférerais que ce soit l'inverse, eh bien.
yoyo
6

Sur certains systèmes (Windows avec VC vient à l'esprit, actuellement), RAND_MAXest ridiculement petit, i. e. seulement 15 bits. Lorsque vous divisez par, RAND_MAXvous ne générez qu'une mantisse de 15 bits au lieu des 23 bits possibles. Cela peut ou non être un problème pour vous, mais vous manquez certaines valeurs dans ce cas.

Oh, je viens de remarquer qu'il y avait déjà un commentaire pour ce problème. Quoi qu'il en soit, voici un code qui pourrait résoudre ce problème pour vous:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

Non testé, mais pourrait fonctionner :-)

Joey
la source
Qu'en est-il de float r = (float) ((rand () << 9) | rand ()) / RAND_MAX? (également non testé)
Piège
Argh, désolé, diviser par RAND_MAX ne vous mènera nulle part ... le but de cette astuce était d'avoir quelque chose de plus grand que RAND_MAX ... corrigé cela pour moi aussi.
Joey
2
Soyez prudent lorsque vous composez des nombres aléatoires sans théorie ... les appels consécutifs à rand () peuvent ne pas être complètement indépendants. Astuce: s'il s'agit d'un générateur congruentiel linéaire, surveillez le bit bas lors d'appels consécutifs: il alterne entre 0 et 1.
RBerteig
Je connais. Pour certaines applications, cela peut cependant suffire. Mais oui, vous devriez probablement utiliser plus de deux appels dans ce cas. Il n'y a pas de solution miracle dans ce cas, vous ne pouvez même pas compter sur le fait qu'il s'agit d'un LCG. D'autres PRNG ont des bits hauts faibles. La solution Boost devrait être la meilleure ici.
Joey
(nb: le bit faible renvoyé par rand dans MSVC n'est pas le bit le plus bas de l'état RNG. Pour les appels à 100 rand (), j'obtiens ce qui suit: 1100100000111111101010010010011010101110110110111010011111100100000000010100011011000000100101100011. Java utilise un LCG 48 bits et n'utilise que 32 bits, le VC semble pour le faire de la même façon)
Joey
4

drand48(3)est la méthode standard POSIX. Glibc fournit également une version rentrante, drand48_r(3).

La fonction a été déclarée obsolète dans SVID 3 mais aucune alternative adéquate n'a été fournie, donc IEEE Std 1003.1-2013 l' inclut toujours et n'a aucune note que cela va n'importe quand de sitôt.

Sous Windows, la méthode standard est CryptGenRandom () .

ivan_pozdeev
la source
2

Je n'ai été satisfait par aucune des réponses jusqu'à présent, j'ai donc écrit une nouvelle fonction flottante aléatoire. Il fait des hypothèses au niveau du bit sur le type de données float. Il a toujours besoin d'une fonction rand () avec au moins 15 bits aléatoires.

//Returns a random number in the range [0.0f, 1.0f).  Every
//bit of the mantissa is randomized.
float rnd(void){
  //Generate a random number in the range [0.5f, 1.0f).
  unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand()));
  unsigned short coinFlips;

  //If the coin is tails, return the number, otherwise
  //divide the random number by two by decrementing the
  //exponent and keep going. The exponent starts at 63.
  //Each loop represents 15 random bits, a.k.a. 'coin flips'.
  #define RND_INNER_LOOP() \
    if( coinFlips & 1 ) break; \
    coinFlips >>= 1; \
    ret -= 0x800000
  for(;;){
    coinFlips = rand();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    //At this point, the exponent is 60, 45, 30, 15, or 0.
    //If the exponent is 0, then the number equals 0.0f.
    if( ! (ret & 0x3F800000) ) return 0.0f;
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
  }
  return *((float *)(&ret));
}
iNFiNiTyLoOp
la source
7
approche intéressante, je voudrais voter mais, je ne comprends vraiment pas ce qui se passe
hasen
2

À mon avis, la réponse ci-dessus donne un flottant «aléatoire», mais aucun d'entre eux n'est vraiment un flottant aléatoire (c'est-à-dire qu'il manque une partie de la représentation du flotteur). Avant de me précipiter dans mon implémentation, examinons d'abord le format standard ANSI / IEEE pour les flottants:

| signe (1 bit) | e (8 bits) | f (23 bits) |

le nombre représenté par ce mot est (-1 * signe) * 2 ^ e * 1.f

notez que le nombre «e» est un nombre biaisé (avec un biais de 127) allant de -127 à 126. La fonction la plus simple (et en fait la plus aléatoire) consiste à simplement écrire les données d'un int aléatoire dans un flottant, Donc

int tmp = rand();
float f = (float)*((float*)&tmp);

notez que si vous le faites, float f = (float)rand();il convertira l'entier en un flottant (ainsi 10 deviendra 10,0).

Alors maintenant, si vous voulez limiter la valeur maximale, vous pouvez faire quelque chose comme (je ne sais pas si cela fonctionne)

int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f       // note float to int conversion!
tmp %= max_number;
f -= tmp;

mais si vous regardez la structure du flotteur, vous pouvez voir que la valeur maximale d'un flotteur est (environ) 2 ^ 127 qui est beaucoup plus grande que la valeur maximale d'un int (2 ^ 32) excluant ainsi une partie importante de les nombres qui peuvent être représentés par un flotteur. Ceci est ma mise en œuvre finale:

/**
 * Function generates a random float using the upper_bound float to determine 
 * the upper bound for the exponent and for the fractional part.
 * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
 * @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
 * @param sign_flag if sign_flag = 0 the random number is always positive, if 
 *              sign_flag = 1 then the sign bit is random as well
 * @return a random float
 */
float randf(int min_exp, int max_exp, char sign_flag) {
    assert(min_exp <= max_exp);

    int min_exp_mod = min_exp + 126;

    int sign_mod = sign_flag + 1;
    int frac_mod = (1 << 23);

    int s = rand() % sign_mod;  // note x % 1 = 0
    int e = (rand() % max_exp) + min_exp_mod;
    int f = rand() % frac_mod;

    int tmp = (s << 31) | (e << 23) | f;

    float r = (float)*((float*)(&tmp));

    /** uncomment if you want to see the structure of the float. */
//    printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);

    return r;
}

l'utilisation de cette fonction randf(0, 8, 0)renvoie un nombre aléatoire compris entre 0,0 et 255,0

user2546926
la source
1
vous avez une erreur. rand ()% frac_mod ne fonctionnera pas car MAX_RAND est généralement inférieur à (1 << 23).
DanielHsH
Je dois admettre que je ne connais pas la taille exacte de MAX_RAND. Néanmoins, cela fonctionnera toujours, c'est peut-être une déclaration inutile, mais cela fonctionnera toujours. 8% 10 = 8 donc c'est très bien, mais si MAX_RAND est toujours plus petit alors (1 << 23) vous pouvez en effet le supprimer.
user2546926
2
Non, vous vous trompez un peu. RandMax est généralement d'environ 65 000. Cela signifie qu'à partir de 23 bits, vous ne faites que 15 au hasard. Les autres seront probablement nuls. Vous obtiendrez en effet des nombres aléatoires mais de faible précision. Par exemple, votre générateur aléatoire peut générer 0,001 et 0,002 mais ne peut pas générer 0,0017. Vous avez donc une distribution uniforme mais de faible précision (256 fois moins de précision que le flotteur).
DanielHsH
Il y a deux erreurs dans cette réponse. Fixer la gamme des exposants: int e = (rand() % (max_exp - min_exp)) + min_exp_mod;et la mantisse: int f = (int)(frac_mod * (float)rand() / RAND_MAX);remplacer leurs lignes respectives ci-dessus. Notez que l'erreur de mantisse est majeure: pour les RAND_MAXplus petits, 1 << 23vous ne randomisez que les bits de poids faible et obtenez tout le temps les 0 pour les bits de poids fort!
BeyelerStudios
2

Si vous savez que votre format à virgule flottante est IEEE 754 (presque tous les processeurs modernes, y compris Intel et ARM), vous pouvez créer un nombre à virgule flottante aléatoire à partir d'un entier aléatoire à l'aide de méthodes binaires. Cela ne doit être pris en compte que si vous n'avez pas accès aux C ++ 11 randomou Boost.Randomqui sont tous les deux bien meilleurs.

float rand_float()
{
    // returns a random value in the range [0.0-1.0)

    // start with a bit pattern equating to 1.0
    uint32_t pattern = 0x3f800000;

    // get 23 bits of random integer
    uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());

    // replace the mantissa, resulting in a number [1.0-2.0)
    pattern |= random23;

    // convert from int to float without undefined behavior
    assert(sizeof(float) == sizeof(uint32_t));
    char buffer[sizeof(float)];
    memcpy(buffer, &pattern, sizeof(float));
    float f;
    memcpy(&f, buffer, sizeof(float));

    return f - 1.0;
}

Cela donnera une meilleure distribution que celle utilisant la division.

Mark Ransom
la source
8
Je ne sais pas pourquoi vous dites que cela donnerait une "meilleure distribution". En fait, cela donnera exactement la même distribution que juste return (float)random23 / (1 << 23). (Oui, je viens de tester cela , en modifiant votre fonction pour prendre random32en paramètre et en l'exécutant pour toutes les valeurs de zéro à (1 << 23)-1. Et oui, votre méthode donne en effet exactement les mêmes résultats que la division par 1 << 23.)
Ilmari Karonen
1

Pour C ++, il peut générer de vrais nombres flottants dans la plage spécifiée par la distvariable

#include <random>  //If it doesnt work then use   #include <tr1/random>
#include <iostream>

using namespace std;

typedef std::tr1::ranlux64_base_01 Myeng; 
typedef std::tr1::normal_distribution<double> Mydist;

int main() { 
       Myeng eng; 
       eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970);
       Mydist dist(1,10); 

       dist.reset(); // discard any cached values 
       for (int i = 0; i < 10; i++)
       {
           std::cout << "a random value == " << (int)dist(eng) << std::endl; 
       }

       return (0);
}
Marco167
la source
1
Vous venez de copier et coller le code de cette réponse? stackoverflow.com/a/1118739/1538531
Derek
En fait non. Je suis un peu surpris de voir à quel point ils se ressemblent! Mais j'ai initialisé le moteur-générateur le 1er janvier 1970.
Marco167
C'est suffisant. J'ai remarqué que vous avez initialisé le générateur à l'époque, mais sacrément ce code est similaire!
Derek
Je trouve un peu étrange de donner un exemple TR1, pouvez-vous expliquer dans quels cas quelqu'un devrait utiliser TR1 par opposition à C ++ 11?
Shafik Yaghmour
0

rand () retourne un int entre 0 et RAND_MAX. Pour obtenir un nombre aléatoire entre 0,0 et 1,0, commencez par convertir le retour int par rand () en un flottant, puis divisez par RAND_MAX.

James Curran
la source
0
#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

/* single precision float offers 24bit worth of linear distance from 1.0f to 0.0f */
float getval() {
    /* rand() has min 16bit, but we need a 24bit random number. */
    uint_least32_t r = (rand() & 0xffff) + ((rand() & 0x00ff) << 16);
    /* 5.9604645E-8 is (1f - 0.99999994f), 0.99999994f is the first value less than 1f. */
    return (double)r * 5.9604645E-8;
}

int main()
{
    srand(time(NULL));
...

Je n'ai pas pu poster deux réponses, voici donc la deuxième solution. log2 nombres aléatoires, biais massif vers 0,0f mais c'est vraiment un flottant aléatoire de 1,0f à 0,0f.

#include <cstdint>
#include <cstdlib>
#include <ctime>

using namespace std;

float getval () {
    union UNION {
        uint32_t i;
        float f;
    } r;
    /* 3 because it's 0011, the first bit is the float's sign.
     * Clearing the second bit eliminates values > 1.0f.
     */
    r.i = (rand () & 0xffff) + ((rand () & 0x3fff) << 16);
    return r.f;
}

int main ()
{
    srand (time (NULL));
...
Mike Mestnik
la source