web-dev-qa-db-fra.com

Pourquoi C ++ Rand () semble-t-il générer uniquement des nombres du même ordre de grandeur?

Dans une petite application écrite en C/C++, je suis confronté à un problème avec la fonction Rand et peut-être la graine:

Je veux produire une séquence de nombres aléatoires qui sont d'ordres différents, c'est-à-dire avec différentes valeurs de logarithme (base 2). Mais il semble que tous les nombres produits soient du même ordre, fluctuant juste entre 2 ^ 25 et 2 ^ 30.

Est-ce parce que Rand() est ensemencé avec du temps Unix qui est maintenant un nombre relativement important? Qu'est-ce que j'oublie? Je ne sème Rand() qu'une seule fois au début de main().

146
Tallaron Mathias

Il n'y a que 3% des nombres entre 1 et 230 qui ne sont PAS entre 225 et 230. Donc, cela semble assez normal :)

Parce que 225 / 230 = 2-5 = 1/32 = 0,03125 = 3,125%

478
C4stor

Le vert plus clair est la région entre 0 et 225; le vert plus foncé est la région entre 225 et 230. Les tiques sont des puissances de 2.

distribution

272
Casey Chu

Vous devez être plus précis: vous voulez des valeurs de logarithme en base 2 différentes mais que distribution voulez-vous pour cela? Les fonctions standard Rand () génèrent une distribution uniforme, vous devrez transformer cette sortie en utilisant la fonction quantile associée à la distribution que vous souhaitez.

Si vous nous indiquez la distribution, nous pouvons vous indiquer la fonction quantile dont vous avez besoin.

42
Bathsheba

Si vous voulez des ordres de grandeur différents, pourquoi ne pas simplement essayer pow(2, Rand())? Ou peut-être choisir directement l'ordre comme Rand (), comme Harold l'a suggéré?

18
aspiring_sarge

La réponse de base (et correcte) a déjà été donnée et acceptée ci-dessus: il y a 10 nombres entre 0 et 9, 90 nombres entre 10 et 99, 900 entre 100 et 999, etc.

Pour un moyen de calcul efficace d'obtenir une distribution avec approximativement distribution logarithmique, vous voulez décaler votre nombre aléatoire vers la droite par un nombre aléatoire:

s = Rand() & 31; // a random number between 0 and 31 inclusive, assuming Rand_MAX = 2^32-1
r = Rand() >> s; // right shift

Ce n'est pas parfait, mais c'est beaucoup plus rapide que de calculer pow(2, Rand()*scalefactor). Il sera "grumeleux" dans le sens où la distribution sera uniforme pour les nombres dans un facteur 2 (uniforme pour 128 à 255, moitié de la densité pour 256 à 1023, etc.).

Voici un histogramme de la fréquence des nombres 0 à 31 (en échantillons 1M):

enter image description here

13
Floris

@ C4stor a fait un excellent point. Mais, pour un cas plus général et plus facile à comprendre pour l'homme (base 10): pour la plage de 1 à 10 ^ n, ~ 90% des nombres sont de 10 ^ (n-1) à 10 ^ n, par conséquent, ~ 99% des nombres vont de 10 ^ (n-2) à 10 ^ n. Continuez à ajouter autant de décimales que vous le souhaitez.

Mathématiques drôles, si vous continuez à faire cela pour n, vous pouvez voir que de 1 à 10 ^ n, 99,9999 ...% = 100% des nombres sont de 10 ^ 0 à 10 ^ n avec cette méthode.

Maintenant, à propos du code, si vous voulez un nombre aléatoire avec des ordres de grandeur aléatoires, de 0 à 10 ^ n, vous pouvez faire:

  1. Génère un petit nombre aléatoire de 0 à n

  2. Si vous connaissez la plage de n, générez un grand nombre aléatoire d'ordre 10 ^ k où k> max {n}.

  3. Coupez le nombre aléatoire le plus long pour obtenir les n chiffres de ce grand nombre aléatoire.

13

Il y a un nombre de nombres exactement égal entre 0 et 2 ^ 29 et 2 ^ 29 et 2 ^ 30.

Une autre façon de voir le problème: considérez la représentation binaire du nombre aléatoire que vous générez, la probabilité que le bit le plus élevé soit 1 est égal à 1/2 et, par conséquent, vous obtenez l'ordre 29 dans la moitié des cas. Ce que vous voulez, c'est voir un nombre qui serait inférieur à 2 ^ 25, mais cela signifie que les 5 bits les plus élevés sont tous nuls, ce qui se produit avec une faible probabilité de 1/32. Les chances sont que même si vous l'exécutez pendant longtemps, vous ne verrez jamais du tout l'ordre inférieur à 15 (la probabilité est quelque chose comme rouler 6 6 fois de suite).

Maintenant, la partie de votre question sur la graine. Non, la graine ne peut pas déterminer la plage à partir de laquelle les nombres sont générés, elle détermine simplement le premier élément initial. Considérez Rand () comme une séquence de tous les nombres possibles dans la plage (permutation prédéterminée). La graine détermine où vous commencez à dessiner des nombres à partir de la séquence. C'est pourquoi si vous voulez (pseudo) aléatoire, vous utilisez l'heure actuelle pour initialiser la séquence: peu importe que la position à partir de laquelle vous partez ne soit pas uniformément répartie, tout ce qui compte c'est que vous ne partez jamais de la même position.

5
Vadim

utilisez pow(2,Rand()) il donnera les réponses dans l'ordre de grandeur souhaité !!

2
Shivendra

Si vous souhaitez utiliser des nombres aléatoires à partir d'un service en ligne, vous pouvez utiliser wget pour cela, vous pouvez voir que vous pouvez également utiliser des services comme random.org pour votre génération de nombres aléatoires, vous pouvez les attraper en utilisant wget, puis en lisant les nombres à partir de le fichier téléchargé

wget -q https://www.random.org/integers/?num=100&min=1&max=100&col=5&base=10&format=html&rnd=new -O new.txt

http://programmingconsole.blogspot.in/2013/11/a-better-and-different-way-to-generate.html

2
Namit Sinha