2011-02-16 14 views
2

Je sais qu'il y a un peu de limitations pour une génération de nombres aléatoires en C++ (peut être non uniforme). Comment puis-je générer un nombre de 1 à 14620?Générateur de nombres aléatoires, C++

Merci.

+0

vous avez fait maintenant même lever les yeux comment utiliser des nombres aléatoires en C++? Vous avez également omis d'indiquer si vous aviez besoin d'une meilleure solution pour construire des nombres aléatoires en C++ ou simplement pour savoir comment utiliser rand. – thecoshman

+0

pourriez-vous préciser ce que vous entendez par "limitations pour une génération de nombres aléatoires" spécifique à C++? Les séquences plus ou moins uniformes proviennent de générateurs meilleurs ou moins bons. – Francesco

+0

Si rand() était (peut être non uniforme), cela ne serait pas très utile. –

Répondre

17

Une approche commune est d'utiliser std::rand() avec un modulo:

#include<cstdlib> 
#include<ctime> 

// ... 
std::srand(std::time(0)); // needed once per program run 
int r = std::rand() % 14620 + 1; 

Cependant, comme @tenfour mentionne dans sa réponse, l'opérateur modulo peut perturber l'uniformité des valeurs std::rand() renvoie. C'est parce que le modulo traduit les valeurs qu'il rejette en valeurs valides, et cette traduction peut ne pas être uniforme. Par exemple, pour n dans [0, 10) la valeur n % 9 traduit 9 à 0, de sorte que vous pouvez obtenir zéro par un vrai zéro ou un 9 traduit à zéro. Les autres valeurs ont chacune une seule chance de céder.

Une autre approche consiste à convertir le nombre aléatoire de std::rand() en une valeur à virgule flottante dans la plage [0, 1), puis de traduire et de déplacer la valeur dans la plage souhaitée.

int r = static_cast<double>(std::rand())/RAND_MAX * 14620 + 1; 
4

Utilisez rand.

(rand() % 100) is in the range 0 to 99 
(rand() % 100 + 1) is in the range 1 to 100 
(rand() % 30 + 1985) is in the range 1985 to 2014 

(rand() % 14620 + 1) is in the range 1 to 14620 

EDIT:

Comme mentionné dans le lien, la randomizer devrait être ensemencé en utilisant srand avant utilisation. Une valeur distinctive commune à utiliser est le résultat d'un appel à time.

+3

Vous avez omis l'important addenda: * Remarquez cependant que cette opération modulo ne génère pas un nombre aléatoire réellement uniformément distribué dans l'intervalle * – meagar

+0

Droite, pas sans semer. Le lien mentionne l'ensemencement au bas de la page. Je vais mettre à jour pour inclure cela. – James

+0

@James, @meagar, Comment pourrais-je générer un nombre aléatoire distribué vraiment uniforme? Je dois générer 30 000 d'entre eux dans une seule boucle de l'algorithme. – notrockstar

11

srand()/rand() sont les fonctions dont vous avez besoin, comme d'autres ont répondu.

Le problème avec % est que le résultat est décidément non uniforme. Pour illustrer, imaginez que rand() renvoie une plage de 0-3. Voici les résultats hypothétiques de l'appeler 4000 fois:

0 - 1000 times 
1 - 1000 times 
2 - 1000 times 
3 - 1000 times 

Maintenant, si vous faites la même échantillonnage pour (rand() % 3), vous remarquerez que les résultats seraient comme:

0 - 2000 times 
1 - 1000 times 
2 - 1000 times 

Aïe! La solution la plus uniforme est la suivante:

int n = (int)(((((double)std::rand())/RAND_MAX) * 14620) + 1);

Désolé pour le code bâclée, mais l'idée est de le réduire correctement à la plage que vous voulez en utilisant les mathématiques à virgule flottante, et convertir en entier.

+0

: +1 Bon point. – wilhelmtell

+0

'(((double) std :: rand())/RAND_MAX)' - pouvez-vous s'il vous plaît expliquer cette partie ici? Générez-vous un nombre aléatoire et l'augmentez par RAND_MAX? – notrockstar

+0

en divisant par «RAND_MAX», vous générez un nombre aléatoire uniforme entre 0.0 et 1.0. Cela le rend simple à l'échelle pour les limites que vous voulez. Dans votre cas, 1-14620. – tenfour

18

Si vous avez un C++ 0x environnement, un dérivé fin de la lib boost est maintenant standard:

#include <random> 
#include <iostream> 

int main() 
{ 
    std::uniform_int_distribution<> d(1, 14620); 
    std::mt19937 gen; 
    std::cout << d(gen) << '\n'; 
} 

Ce sera rapide, facile et la qualité élevée.

Vous ne précisaient pas, mais si vous voulez en virgule flottante à la place juste sous dans:

std::uniform_real_distribution<> d(1, 14620); 

Et si vous avez besoin d'une distribution non uniforme, vous pouvez construire votre propre constante sage morceau ou par morceaux sage distribution linéaire très facilement.

+0

Notez qu'il existe une différence importante entre l'uniform uniform et les distributions réelles uniformes. La distribution int uniforme renvoie des nombres dans la "plage fermée" [1,14620] tandis que la distribution réelle uniforme renvoie des nombres dans la "plage semi-ouverte" [1,14620]. – Blastfurnace

+1

Pourrait également utiliser le semis C++ 0x-esque, 'std :: random_device r; std :: mt19937 gen (r()); ' – Cubbi

+0

Et si vous n'avez pas C++ 0x, boost :: random devrait probablement être votre standard, sauf si vous avez vraiment besoin de quelque chose de rapide et sale ... – Chinasaur

1

Comme déjà dit, vous pouvez utiliser rand(). Par exemple.

int n = rand() % 14620 + 1;

fait le travail, mais il est non uniforme. Cela signifie que certaines valeurs (valeurs faibles) apparaîtront légèrement plus fréquemment. En effet, rand() donne des valeurs comprises entre 0 et RAND_MAX et RAND_MAX n'est généralement pas divisible par 14620. Par exemple. si RAND_MAX == 15000, alors le nombre 1 serait deux fois plus probable que le nombre 1000 car rand() == 0 et rand() == 14620 donnent tous les deux n==1 mais seulement rand()==999 rend n==1000 vrai.

Cependant, si 14620 est beaucoup plus petit que RAND_MAX, cet effet est négligeable. Sur mon ordinateur RAND_MAX est égal à 2147483647. Si rand() donne des échantillons uniformes entre 0 et RAND_MAX alors, parce que 2147483647% 14620 = 10327 et 2147483647/14620 = 146886, n serait entre 1 et 10328 en moyenne 146887 fois tandis que les numéros entre 10329 et 14620 se produirait en moyenne 146886 fois si vous dessinez 2147483647 échantillons. Pas beaucoup de différence si vous me demandez.

Cependant, si RAND_MAX == 15000, cela ferait une différence comme expliqué ci-dessus. Dans ce cas, certains postes précédents ont suggéré d'utiliser

int n = (int)(((((double)std::rand())/RAND_MAX) * 14620) + 1);

pour le rendre « plus uniforme ». Notez que cela ne change que les numéros qui se produisent plus fréquemment puisque rand() renvoie toujours «seulement» RAND_MAX valeurs distinctes. Pour que ce soit vraiment uniforme, vous devez rejeter toute forme entière rand() si elle est comprise entre 14620 * int (RAND_MAX/14620) et RAND_MAX et appeler à nouveau rand(). Dans l'exemple avec RAND_MAX == 15000 vous rejetter toutes les valeurs de rand() entre 14620 et 15000 et dessiner à nouveau. Pour la plupart des applications, cela n'est pas nécessaire. Je m'inquiéterais plus au sujet du hasard de rand().

0

l'opérateur de module est le plus important, vous pouvez appliquer une limite avec ce module, vérifier cela:

// random numbers generation in C++ using builtin functions 
#include <iostream> 

using namespace std; 

#include <iomanip> 

using std::setw; 

#include <cstdlib> // contains function prototype for rand 

int main() 
{ 
// loop 20 times 
for (int counter = 1; counter <= 20; counter++) { 

    // pick random number from 1 to 6 and output it 
    cout << setw(10) << (1 + rand() % 6); 

    // if counter divisible by 5, begin new line of output 
    if (counter % 5 == 0) 
     cout << endl; 

} 

return 0; // indicates successful termination 

} // end main 
1

La fonction rand() n'est pas vraiment le meilleur générateur aléatoire, une meilleure façon serait en utilisant CryptGenRandom().

Cet exemple devrait ne faire l'affaire:

#include <Windows.h> 

// Random-Generator 
HCRYPTPROV hProv; 
INT Random() { 
    if (hProv == NULL) { 
     if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) 
      ExitProcess(EXIT_FAILURE); 
    } 

    int out; 
    CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out)); 
    return out & 0x7fffffff; 
} 

int main() { 
    int ri = Random() % 14620 + 1; 
} 
Questions connexes