[C/C++] Générer beaucoup de nombres aléatoire

Résolu/Fermé
Ortoli - 15 févr. 2007 à 00:14
mamiemando Messages postés 33304 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 octobre 2024 - 6 janv. 2012 à 20:18
B'jour les gens,

Bon, je crains que ça fasse noube de demander, d'autant que vu le nombre de réponses sur les forums... Je sais, j'ai été modo moi aussi, et je pense bien avoir tout essayé. Enfin, non, pas tout, puisque je n'ai pas encore trouvé ;)

Il faut que je génère un grand nombre de nombres aléatoires (simulation de lois normales, si vous voulez tout savoir), le tout en C/C++.

Alors, au début du main, une seule fois :
srand((unsigned int) time(NULL));


Un flottant entre 0 et 1 me suffirait parfaitement - donc
pif = (float)rand() / ((float)RAND_MAX + 1.0) ;


Le problème est que je génère pif50 fois à la suite pour avoir une loi normale (théorème central limite, pour ceuces que ça intéresse), puis 2000 fois, puis re-1825 fois (5 * 365). Et, comme vous vous en doutez, ben je tombe toujours sur les mêmes nombres.

La seule solution que j'ai trouvée pour le moment est d'attendre une seconde, et pas moins, (Sleep(1000);) entre chaque tirage - ce qui n'est pas possible, à moins d'avoir trente ans à paumer...

Retirer la graine à chaque tirage (genre
for (i) {srand (i) ; rand();}
) ne fonctionne pas non plus.

Une idée, quelqu'un ?

15 réponses

mamiemando Messages postés 33304 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 octobre 2024 7 794
15 févr. 2007 à 03:10
Ah oui mais en fait c'est parce que la graine devrait être initialisée une et une seule fois
http://www-fourier.ujf-grenoble.fr/~parisse/tdp0/node55.html

Bonne chance
6
mamiemando Messages postés 33304 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 octobre 2024 7 794
3 juil. 2008 à 19:50
Depuis un an et demi je pense qu'il a trouvé ;-)
3
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
15 févr. 2007 à 09:05
Salut.
Je pense que le générateur de nombre aléatoire standard n'est pas suffisant pour ce que tu veux faire.
Je pense qu'il ajouter une nouvelle fonction.
J'en ai trouvé une, sur la Gnu Scientific Library (GSL 1.5) qui comporte plusieurs fonctions random. Peut être seraient elles mieux...
2
Sinon tu fais un tableau de nombres aléatoires, tu prends au hasard le nombre d'une case de ce tableau et tu le remplac e par un autre nombre aléatoire.

un site intéressant sur le sujet :
http://www.games-creators.org/wiki/Les_nombres_al%C3%A9atoires:_la_fonction_rand()_en_C
2

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33304 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 octobre 2024 7 794
15 févr. 2007 à 10:09
Sinon en boost il y a aussi des outils intéressant pour générer des nombres aléatoire, et même simplement avec la STL
1
Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007 94
15 févr. 2007 à 10:29
La fonction rand n'est pas une réelle fonction aléatoire, elle génère un nombre à partir d'un algo compliqué qui tire sa variable à partir du processeur (je crois que c'est l'horloge mais pas sûr).

Pour avoir un semblant de random sur 2000 valeurs assez rapidement, le plus simple (mais c'est de la bidouille), c'est d'affecter des coefficients rand () les uns aux autres, par exemple tu fais un cosinus d'un rand multiplié par un rand etc etc...
Par contre il faudra déterminer les valeurs max et min en pratique car les multiplications déportent la place de la virgule souvent (genre tu peux passer de 0.X à 0.00X) et il faut adapter aux valeurs dont tu as besoin. Attention aux additions, n'oublie pas de tester si tout rand sort 1 (fonctions magiques pour les additions : cos et sin !)

Voilou
1
'rci à tous !

Bon, alors, effectivement, le rand() suffisait pas. Apparemment, quand il a besoin de tout plein de valeurs au pif rapidement, il reprend certaines d'avant (d'où une sorte de période, des séquences de 50 qui se répètaient plusieurs fois). Ca, un cycle possible, une fonction pas super entropique => yapabon.

Pour répondre, dans l'ordre...

Mamiemando, effectivement, le srand(time(0)) ne se fait qu'une seule fois - c'était mon cas ;) Je n'ai pas cherché avec boost, ayant trouvé avant... A creuser, je le garde dans un coin.

Char Snipeur, j'étais aussi tombé sur la GSL, mais... même réponse que mamiemando, trouvé avant, faudrait creuser, toussa.

Stupeflip, après m'êtrepris la tête dessus pendant 4h, j'ai même ressorti le Knuth, le Schneier et toute la clique. Apparemment, von Neumann aurait dit "Anyone who considers arithmetical methods of producing random digits is, of course, in a state of sin." et comme c'était pas la moitié d'un imbécile, j'ai laissé tomber la méthode.

Quoiqu'il en soit, j'ai trouvé au hasard d'un forum le bout de code suivant :
unsigned long prng(unsigned long state)
{
 return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
}

(apparemment utilisé par entre autres vlc pour les sons). Je n'ai pas tout pigé, une sorte de /dev/random pour les pauvres ?

En gros, si ça peut servir à quelqu'un :
-> srand((unsigned int) time(NULL)); dans le main au tout début
-> cette fonction prng() {}
-> prng(rand()) pour avoir un nombre au pif entre -2^31 et 2^31
1
Salut, quand tu fais pif = (float)rand() / ((float)RAND_MAX + 1.0) ; tu génère un nombre pseudo-aléatoire suivant la loi uniforme et non la loi normale. Voici ce que je fais pour la loi normale :

#define TWOPI (6.2831853071795864769252867665590057683943387987502) /* 2 * pi */

/* 
   RAND is a macro which returns a pseudo-random numbers from a uniform
   distribution on the interval [0 1]
*/
#define RAND (rand())/((double) RAND_MAX)

/* 
   RANDN is a macro which returns a pseudo-random numbers from a normal
   distribution with mean zero and standard deviation one. This macro uses Box
   Muller's algorithm
*/
#define RANDN (sqrt(-2.0*log(RAND))*cos(TWOPI*RAND))


double NormalDistribution(double mu,double sigma)
{
/*
   This function returns a pseudo-random number from a normal distribution with
   mean equal at mu and standard deviation equal at sigma > 0
*/
  if(sigma<=0.)
  {
    fprintf(stderr,"Error in file %s line %u function %s : sigma must be > 0\nExit program\n",__FILE__,__LINE__,__FUNCTION__);
    MPI_Finalize();
    exit(EXIT_FAILURE);
  }
  
  return (mu+sigma*RANDN);

}


et tu fais ensuite une boucle for pour tirer 50000 tirages.
1
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
15 févr. 2007 à 17:28
comprend pas...
pour moi le &0xffffffffL reviens à ne rien faire car un 'et' bit à bit avec que des '1'...
ensuite, je voi pas ou est l'aléatoire, si tu prend deux foi le même "state", tu aura deux foi le même 'prng'. Tu pourrai traduire la phrase de Von Neumann ?
1
// Tri selection
////////////////
static Liste Tri_Selection_Liste(Liste l)
{
if (l == null)
return null ;

// Recherche du minimum : attention au decalage d'un cran de l1 et l2
Liste l1 = l, l2 = null ; ;
int min = l.elt ;
while (l1.suivant != null) {
if (l1.suivant.elt < min) {
min = l1.suivant.elt ;
l2 = l1 ;
}
l1 = l1.suivant ;
}

// On supprime le minimum de la liste
if (l2 == null) {
l.suivant = Tri_Selection_Liste(l.suivant) ;
return l ;
}
else {
l1 = l2.suivant ;
l2.suivant = l2.suivant.suivant ;
l1.suivant = Tri_Selection_Liste(l) ;
return l1 ;
}
}

// Tri insertion
////////////////
static Liste Tri_Insertion_Liste(Liste l)
{
// On prend le premier element
Liste l2 = l ;
l = l.suivant ;
l2.suivant = null ;

// On ajoute les elements suivants
while (l != null) {
if (l.elt < l2.elt) {
Liste l1 = l ;
l = l.suivant ;
l1.suivant = l2 ;
l2 = l1 ;
}
else {
Liste l1 = l ;
l = l.suivant ;
l1.suivant = null ;
Ajout_Trie_Liste(l2, l1) ;
}
}
return l2 ;
}

// Fonction d'ajout d'un element dans une liste triee
static void Ajout_Trie_Liste(Liste l, Liste l1) {
if (l.suivant == null) {
l.suivant = l1 ;
}
else if (l1.elt < l.suivant.elt) {
l1.suivant = l.suivant ;
l.suivant = l1 ;
}
else
Ajout_Trie_Liste(l.suivant, l1) ;
}
bonsoir tu peut m'aider a trduire ce code de java au pascal
merci
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
16 févr. 2007 à 15:50
ok, merci pour la traduction.
La méthode prng resemble à une méthode arithmétique, ou il y a un truc qui m'échape.
0xffffffff c'est surement un masque, mais pour moi c'est un masque qui fait rien, qui laisse tout passer car tout les bit du nombre sont à 1. Si qqun pouvai expliquer cette fonction prng, pasque pour moi elle est bidon.
0
bebetoalvaro Messages postés 14 Date d'inscription vendredi 5 janvier 2007 Statut Membre Dernière intervention 16 février 2007
16 févr. 2007 à 16:20
tu peux me repondre a ma question
c comment trier les listes chainee
merci
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298 > bebetoalvaro Messages postés 14 Date d'inscription vendredi 5 janvier 2007 Statut Membre Dernière intervention 16 février 2007
17 févr. 2007 à 16:28
salut bebe,
je ne répondrai pas à ta question ici.
Déjà parceque ce n'est pas le sujet du présent message (random tout ça) Ensuite, parceque tu ne pose pas de question. Tu demande de l'aide, je veux bien t'en fournir, mais faire de la traduction, j'ai pas envie de la faire à ta place.
donc, ouvre un message, pose une question claire et précise, precise Java<->pascal dans ton titre, et je verrai à te répondre.
0
lirey83 Messages postés 75 Date d'inscription mardi 2 janvier 2007 Statut Membre Dernière intervention 18 août 2007 13
17 févr. 2007 à 14:24
Il y a quantité d'algo sur Internet. Cherche "Random number" avec Google et tu en auras une palanqué. Exemple :
https://www.boost.org/doc/libs/1_72_0/doc/html/boost_random.html

Y a aussi "numerical recipes" ...
0
Bon, ben merci à tous ! Comme je l'ai dit - sans que l'on arrive à comprendre pourquoi, mais je creuse, je vous tiens au courant - j'ai trouvé, et grâce à ce qu'il m'a été proposé plus haut, il me reste quelque pistes. Reste plus qu'à trouver comment marquer le message en "résolu".
0
#include <cstdlib>
#include <cstdio>
#include "iostream"
#include <cmath>
#include <ctime>
#include <vector>
#include <fstream>
using namespace std;

#define a0 double(RAND_MAX)



int main(){
time_t graine;
// A chaque execution vous avez une graine
//càd la graine depend du temps
srand((unsigned)int(time(&graine)));
int i,n;
double x;
FILE *randy; randy=fopen("aleatoire.txt","w+");
// tu donne à n n'importe quelle valeur
cout<<"Entrer le nbre de valeurs:";
cin>>n;
for(i=1;i<=n;i++){
// tu divise seulement par RAND_MAX et non pas par
// (RAND_MAX+1.) et les valeurs de x serront
//dans [0,1]
x=rand()/a0;
fprintf(randy,"i x\n");
cout<<"x["<<i<<"]="<<x<<endl;
}
system("PAUSE");
return 0;
}
0
salut,
je veux bien comprendre comment il fonctionne ce programme??

ou filez moi un lien ou je peurrai trouver des explications, car je suis perdu sur cette énorme toile!!
0
mamiemando Messages postés 33304 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 octobre 2024 7 794
6 janv. 2012 à 20:18
Ouvre un nouveau fil de discussion sur le forum programmation si tu as besoin de précisions (ce sujet est résolu).

Dans l'idée de toute façon le programme ci-dessus n'est pas super bien écrit (il mélange de manière abusive du C et du C++ ou ce n'est pas nécessaire, le system("PAUSE") est à proscrire car spécifique à windows etc...) et bourrés de fautes, donc c'est sans doute pour ça que tu ne le comprends pas.

Accessoirement il ne répond pas à la question.

Dans l'idée, tu peux voir ce que font les fonctions srand, time etc... à l'aide du man (par exemple tape "man srand" dans google ou directement dans un terminal si tu es sous linux). Dans certaines versions du man, tu trouveras même un exemple d'utilisation de srand et de rand, que je te reporte ci-dessous.

Le programme suivant peut être utilisé pour afficher la séquence pseudo-aléatoire produite par rand() avec une graine donnée.

           #include <stdlib.h>
           #include <stdio.h>

           int
           main(int argc, char *argv[])
           {
               int j, r, nloops;
               unsigned int seed;

               if (argc != 3) {
                   fprintf(stderr, "Usage: %s <seed> <nloops>\n", argv[0]);
                   exit(EXIT_FAILURE);
               }

               seed = atoi(argv[1]);
               nloops = atoi(argv[2]);

               srand(seed);
               for (j = 0; j < nloops; j++) {
                   r =  rand();
                   printf("%d\n", r);
               }

               exit(EXIT_SUCCESS);
           }


Bonne chance
0
Stupeflip Messages postés 391 Date d'inscription jeudi 8 février 2007 Statut Membre Dernière intervention 4 décembre 2007 94
16 févr. 2007 à 11:42
C'est un masque le 0xffffff non ?
Sinon la phrase c'est un truc du genre : Toute personne qui s'intéresse aux méthodes arithmétiques pour trouver des algo aléatoires est, bien sur, un peu fou ! :p
-1
Fais un tit tour sur mon site :
http://b.rock.monsite.orange.fr/
rubrique développements
-1