Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1691 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  [C] gestion des nombres aléatoires

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[C] gestion des nombres aléatoires

n°412139
Aricoh
gentil mais fo po pousser
Posté le 01-06-2003 à 11:43:54  profilanswer
 

Bonjour !
 
Comment faites-vous pour gérer les nombres aléatoires en C ???
 
Dans le cadre d'un projet perso, j'ai besoin de concevoir un tout petit code C générant une série de 10 nombres aléatoires compris entre 1 et 10. Un pote m'a filé un bout de code pour générer de l'aléatoire et j'ai fait ce petit exemple que voici :
 
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. #define D10 ((double)rand() / ((double)RAND_MAX + 1) * 10)   + (1)
  5.  
  6. int main(void) {
  7. int i = 10;
  8. srand (time(NULL));
  9. while(i) {
  10.  printf("%d;", D10);
  11.  --i;
  12. }
  13. printf("\n" );
  14. return 0;
  15. }

 
 
Les chiffres générés sont bizarres, il me manque certainement un cast en int car je récupère des valeurs du genre 32765548, -284363, etc à chaque appel de D10.
 
Mais c'est pas ça qui m'inquiète, ce qui me gène bcp c'est que lorsque j'appelle le binaire du programme n fois, je retrouve les mêmes séries très régulièrement.
 
Or, je cherche surtout la manière de générer des nombres aléatoires qui soient VRAIMENT ALEATOIRES.
 
Comment faire ?
 
Aricoh.
 
PS : pros du C, soyez indulgent, je fais pas du C très souvent, mon domaine à moi ---> Perl :)


---------------
Samsung Galaxy S1 -> Samsung Galaxy S2 -> Samsung Note 2 -> Huawei Ascend Mate 7 -> ZTE Axon 7 -> OnePlus 6T -> Oppo Find X2 PRO
mood
Publicité
Posté le 01-06-2003 à 11:43:54  profilanswer
 

n°412141
Taz
bisounours-codeur
Posté le 01-06-2003 à 11:50:41  profilanswer
 
n°412143
Aricoh
gentil mais fo po pousser
Posté le 01-06-2003 à 11:54:31  profilanswer
 

Merci Taz
 
Free merde apparemment, connexion impossible à l'url


---------------
Samsung Galaxy S1 -> Samsung Galaxy S2 -> Samsung Note 2 -> Huawei Ascend Mate 7 -> ZTE Axon 7 -> OnePlus 6T -> Oppo Find X2 PRO
n°412145
Taz
bisounours-codeur
Posté le 01-06-2003 à 11:57:11  profilanswer
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h> /* pour srand, rand et RAND_MAX */
  3. #include <time.h> /* pour time */
  4. #include <math.h>
  5. unsigned my_bad_rand(unsigned N)
  6. {
  7.   /**
  8.    * les bits de poids faibles ont une distribution tres peu aléatoire
  9.    * d'ou des séquences 0 1 0 1 0 1 0 1 0
  10.    * ce n'est donc pas une bonne méthode
  11.    * cette version ne peut renvoyée qu'un entier compris entre 0 et min(RAND_MAX, N)
  12.    * d'ou un usage restreint
  13.    */
  14.   return (unsigned)rand()%N;
  15. }
  16. unsigned my_better_rand(unsigned N)
  17. {
  18.   /**
  19.    * beaucoup plus aléatoire et renvoie un entier entre 0 et N
  20.    * (la je fais pas l'explication :oD )
  21.    */
  22.   return (unsigned)((double)rand()/((double)RAND_MAX+1)*N);
  23. }
  24. double average(const unsigned *tab, unsigned size)
  25. {
  26.   double sum=0.0;
  27.   unsigned i;
  28.  
  29.   for(i=0U; i<size; ++i)
  30.   {
  31.    sum+=tab[i];
  32.   }
  33.  
  34.   return sum/size;
  35. }
  36. int main()
  37. {
  38.   /**
  39.    * initialisation du générateur de nombres pseudos-aleatoires
  40.    * on utilise généralement le temps courant (nombre de secondes ecoulees
  41.    * depuis 01/01/1970)
  42.    * srand => Seed == 'graine'
  43.    */
  44.   srand(time(NULL));
  45.   /* petite routine de test */
  46.   const unsigned N= time(NULL) % RAND_MAX;
  47.   printf("comparaison entre my_bad_rand et my_better_rand\n"
  48.          "nombre d\'iterations (bigger is better) : " );
  49.   unsigned i, size;
  50.   scanf("%u", &size);
  51.  
  52.   unsigned *tab;
  53.   if((tab=malloc(size*sizeof(unsigned))) ==  NULL)
  54.   {
  55.    perror("malloc" );
  56.    exit(EXIT_FAILURE);
  57.   }
  58.   for(i=0U; i<size; ++i)
  59.     {
  60.       tab[i]=my_bad_rand(N);
  61.     }
  62.    
  63.   double bad_avg=average(tab, size) / N;
  64.  
  65.   for(i=0U; i<size; ++i)
  66.     {
  67.       tab[i]=my_better_rand(N);
  68.     }
  69.    
  70.   double better_avg=average(tab, size) / N;
  71.   free(tab);
  72.   printf("my_bad_rand moyenne : %f\n", bad_avg);
  73.   printf("my_better_rand moyenne : %f\n", better_avg);
  74.  
  75.   printf("my_%s_rand gagne !!! (plus aleatoire)\n", (fabs(bad_avg-0.5) < fabs(better_avg-0.5) ? "bad" : "better" ));
  76.   return EXIT_SUCCESS;
  77. }

n°412147
Aricoh
gentil mais fo po pousser
Posté le 01-06-2003 à 11:58:54  profilanswer
 

:jap: ++Taz


---------------
Samsung Galaxy S1 -> Samsung Galaxy S2 -> Samsung Note 2 -> Huawei Ascend Mate 7 -> ZTE Axon 7 -> OnePlus 6T -> Oppo Find X2 PRO
n°412149
Taz
bisounours-codeur
Posté le 01-06-2003 à 12:04:32  profilanswer
 

c juste un petit programme sans doute buggé pour montrer l'interet

n°414214
BifaceMcLe​OD
The HighGlandeur
Posté le 03-06-2003 à 12:21:33  profilanswer
 

Aricoh a écrit :

Bonjour !
 
Comment faites-vous pour gérer les nombres aléatoires en C ???
 
(...)
 
Mais c'est pas ça qui m'inquiète, ce qui me gène bcp c'est que lorsque j'appelle le binaire du programme n fois, je retrouve les mêmes séries très régulièrement.
 
Or, je cherche surtout la manière de générer des nombres aléatoires qui soient VRAIMENT ALEATOIRES.
 
Comment faire ?


Vraiment aléatoires, c'est impossible avec la plupart des machines courantes. Comme leur documentation l'indique, les fonctions rand() et consort donnent accès à un générateur de nombres pseudo-aléatoires. Leur but est de donner des nombres apparemment non liés entre eux. En fait, ce sont les termes d'une suite mathématique toute bête.
 
Donc si tu pars toujours avec le même premier terme de la suite, tu obtiendras toujours les mêmes termes suivants d'une exécuation à l'autre. C'est assez pratique, ceci dit, lorsque tu as un bug dans un programe qui manipule des nombres pseudo-aléatoires, et que tu souhaites reproduire le bug...
 
Cependant, il est assez facile d'obtenir des séquences de nombres pseudo-aléatoires qui changent à chaque exécution. Il suffit de fixer le premier terme de la suite (i.e. initialiser le générateur de nombres pseudo-aléatoires) à une valeur différente à chaque exécution.
 
Pour initialiser le générateur, on utilise la fonction "srand(int seed)". Et pour trouver une valeur différente à chaque exécution, on utilise généralement la valeur que retourne la fonction "time()".
 
Le seul problème résiduel dépend du nombre de tirages que tu fais avec le générateur de nombres pseudo-aléatoires. Si ce nombre de tirages est inférieur à, disons, 5000, alors il n'y a aucun souci. Au-delà, tu risques de retrouver une certaine régularité dans les tirages, et tu devras alors utiliser un autre générateur de nombres pseudo-aléatoires, qui fonctionne avec une résolution supérieure. Le générateur de la librairie standard C est un générateur 16 bits. Mais si tu es sur UNIX, tu dois pouvoir également utiliser un générateur 48 bits (fais un "man rand48" pour plus d'infos).


Message édité par BifaceMcLeOD le 03-06-2003 à 12:23:21
n°414226
Taz
bisounours-codeur
Posté le 03-06-2003 à 12:30:27  profilanswer
 

/dev/random

n°414262
gatorette
Posté le 03-06-2003 à 13:01:10  profilanswer
 

Juste une petite précision (j'ai eu l'occasion de m'y intéresser récemment), tu peux également utiliser d'autres algorithmes de génération de nombre aléatoire. Je pense notamment au Mersenne Twister et tu trouveras pas mal d'infos (si ça t'intéresse) sur le site du pLab.


---------------
each day I don't die is cheating
n°414301
Taz
bisounours-codeur
Posté le 03-06-2003 à 13:49:06  profilanswer
 

ou une lava lamp

mood
Publicité
Posté le 03-06-2003 à 13:49:06  profilanswer
 

n°415614
Aricoh
gentil mais fo po pousser
Posté le 04-06-2003 à 08:04:50  profilanswer
 

Je crois que je vais faire au plus rapide et plus sûr : un module Perl qui gère ces tirages aléatoires.
 
Après moults tests, ce qui pose problème, c'est l'initialisation de l'horloge système. Dès lors que j'insère un srand() dans mon code C, dès que je le lance n fois via un script Perl, je récupère toujours la même série de nombres. Idem si le source C ne contient aucun srand(). Idem si je place mon srand() dans le script Perl et pas dans le source C.
 
Le but de la manip' était de pouvoir exécuter un binaire faisant ces jets aléatoires, les jets étant retournés au programme appelant.


---------------
Samsung Galaxy S1 -> Samsung Galaxy S2 -> Samsung Note 2 -> Huawei Ascend Mate 7 -> ZTE Axon 7 -> OnePlus 6T -> Oppo Find X2 PRO
n°415692
usa_satria​ni
S.P.Q.R.
Posté le 04-06-2003 à 09:44:50  profilanswer
 

Salut !
mon prof m'a filé  ces deux truc : alea.h
 

Code :
  1. #ifndef ALEA_H
  2. #define ALEA_H
  3. void init_alea ();
  4. void init_alea_graine (long graine);
  5. double alea_double();
  6. int alea_int(int maximum);
  7. #endif


 
et alea.c
 

Code :
  1. #include <stdlib.h>
  2. #include <sys/time.h>
  3. #include "alea.h"
  4. void init_alea () {
  5.   struct timeval nowtime;
  6.   gettimeofday(&nowtime, NULL);
  7.   srandom(nowtime.tv_sec^nowtime.tv_usec);
  8. }
  9. void init_alea_graine (long graine) {
  10.   srandom(graine);
  11. }
  12. double alea_double() {
  13.   double res;
  14.   res = (random() % 100000) / 100000.;
  15.   return res;
  16. }
  17. int alea_int(int maximum) {
  18.   return (alea_double() * maximum);
  19. }


 
problèmes : à lécole on bosse sous Sun et moi chui sous windows alors je sais pas si c ca mais dev c ++ me renvoie cette erreur :  

Citation :

In file included from f:\langc\projet\projet.c:2:
f:\langc\projet\alea.c: In function `init_alea':
f:\langc\projet\alea.c:6: storage size of `nowtime' isn't known



---------------
Ce monde n'est qu'une vaste entreprise à se foutre du monde. Céline
n°418809
Angel_Doog​las
Le dernier des humains
Posté le 06-06-2003 à 02:15:25  profilanswer
 

Aricoh a écrit :

Je crois que je vais faire au plus rapide et plus sûr : un module Perl qui gère ces tirages aléatoires.
 
Après moults tests, ce qui pose problème, c'est l'initialisation de l'horloge système. Dès lors que j'insère un srand() dans mon code C, dès que je le lance n fois via un script Perl, je récupère toujours la même série de nombres. Idem si le source C ne contient aucun srand(). Idem si je place mon srand() dans le script Perl et pas dans le source C.
 
Le but de la manip' était de pouvoir exécuter un binaire faisant ces jets aléatoires, les jets étant retournés au programme appelant.


 
Etrange qu'il te rebalance la meme suite meme sans aucune graine (je ne me rappelle plus de l'usage exacte de rand, vu que rand c'est le mal, un tres mauvais generateur). Remarque qu'a priori il repart depuis le debut de la suite a chaque appel (me semblait pas que c'etait le cas mais bon...).
Si tu fais des appels en cascade a ton programme C (et que celui ci est rapide a executer en plus), il faut nourrir la graine avec autre chose que time (par exemple si tu disposes de lecture de "parasites" sur un signal, ca peut le faire) ou alors faire des sleep (le plus facile et le moins elegant :/ mais si le temps machine n'est pas essentiel pourquoi pas) ou encore gerer le pointeur de la suite du rand de maniere a partir de la ou tu t'etais arrete (c'est un peu plus complique).
 
Edit: utilise mersenne twister pour des applis "serieuses".


Message édité par Angel_Dooglas le 06-06-2003 à 02:17:53
n°419053
TheTooN
Posté le 06-06-2003 à 10:52:04  profilanswer
 

moi g fé un script pour ca pour le taf, ca exporte ds un fichier rapport.dat :
 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
main(){
printf("        -= p@ssWoRd g3n3r@t0r PoWeReD by t00n 2003 =-\n" );
srand(time(NULL));
int taille, gener, i, j;
FILE *rapport;
rapport = fopen("rapport.dat", "r+" );
taille = 5;
for(j=0; j<10; j++){
    for(i=0; i<taille; i++){
        gener = rand();
        if(gener<(RAND_MAX / 2)){
                while(gener>122){ gener = gener - 26; }
        } else {
                while(gener>57){ gener = gener - 9; }
        }
    printf("%c", gener);
    fprintf(rapport, "%c", gener);
    }
printf("\n" );
fprintf(rapport, "\n" );
}
fclose(rapport);
 
fclose(passgener);
puts("\nPress a key to finish." ); getch();
}
 
et il fo ke tu ais un fichier rapport.dat vide qui existe paske je me suis po pris la tete à faire des tests et tt et tt vu ke il y a ke moi ki utilise ca.


Message édité par TheTooN le 06-06-2003 à 10:54:36
n°419057
Taz
bisounours-codeur
Posté le 06-06-2003 à 10:55:11  profilanswer
 

c'est loin d'etre un bon générateur dis-donc

n°419091
TheTooN
Posté le 06-06-2003 à 11:12:28  profilanswer
 

ben té dur toi, ca genere des chaines alphanumériques de 5 caractères et ca marche plutot bien - pkoi cé po top ?

n°419100
Taz
bisounours-codeur
Posté le 06-06-2003 à 11:16:17  profilanswer
 

niveau aléa c'est pas le top
 
essaye ça
 

Code :
  1. unsigned my_better_rand(unsigned N)
  2. {
  3. /**
  4.   * beaucoup plus aléatoire et renvoie un entier entre 0 et N
  5.   * (la je fais pas l'explication :oD )
  6.   */
  7. return (unsigned)((double)rand()/((double)RAND_MAX+1)*N);
  8. }


 
tu peux faire par exemple

Code :
  1. c= 'a'+ my_better_rand(26);
  2. d= '0'+ my_better_rand(10);
  3. // ....
  4. if(my_better_rand(2))
  5. {
  6.   c= 'a'+ my_better_rand(26);
  7. }
  8. else
  9. {
  10.   c= '0'+ my_better_rand(10);
  11. }
  12. // ou bien
  13. c=my_better_rand(10+26);
  14. c+= (c < 10 ? '0' : 'a'-10);


 
 
edit: et ça bouffera moins de CPU surtout


Message édité par Taz le 06-06-2003 à 11:25:26
n°419318
LetoII
Le dormeur doit se réveiller
Posté le 06-06-2003 à 13:06:15  profilanswer
 

++Taz a écrit :

niveau aléa c'est pas le top
 
essaye ça
 

Code :
  1. unsigned my_better_rand(unsigned N)
  2. {
  3. /**
  4.   * beaucoup plus aléatoire et renvoie un entier entre 0 et N
  5.   * (la je fais pas l'explication :oD )
  6.   */
  7. return (unsigned)((double)rand()/((double)RAND_MAX+1)*N);
  8. }


 
tu peux faire par exemple

Code :
  1. c= 'a'+ my_better_rand(26);
  2. d= '0'+ my_better_rand(10);
  3. // ....
  4. if(my_better_rand(2))
  5. {
  6.   c= 'a'+ my_better_rand(26);
  7. }
  8. else
  9. {
  10.   c= '0'+ my_better_rand(10);
  11. }
  12. // ou bien
  13. c=my_better_rand(10+26);
  14. c+= (c < 10 ? '0' : 'a'-10);


 
 
edit: et ça bouffera moins de CPU surtout


 
De toute façon rand est pas terrible comem générateur alros bon... :D


---------------
Le Tyran
n°419321
Taz
bisounours-codeur
Posté le 06-06-2003 à 13:08:34  profilanswer
 

alors autant optimiser son utilisation n'est ce pas

n°419327
LetoII
Le dormeur doit se réveiller
Posté le 06-06-2003 à 13:11:26  profilanswer
 

++Taz a écrit :

alors autant optimiser son utilisation n'est ce pas


 
Je parlais au niveau vitesse, juste d'un point de vue qualité des nombres pseudo aléatoire fournis. Après j'ai pas regardé les codes en détails :D


---------------
Le Tyran

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  [C] gestion des nombres aléatoires

 

Sujets relatifs
[Java]Gestion de sources...2 questions : gestion des exceptions et paramètres des fonctions
probleme avec la gestion d'evenement dans une balise divGestion Clients
Gestion de logs, timestamp, TStringList et memogestion bdd
[ASP] Gestion de forumulaire avec nombreux champsPGCD de plus de 2 nombres
J'aimerai bien faire un truc de ce style..(Gestion graphique d'objets)vous connaissez un outil de "gestion de version" a verrouillage
Plus de sujets relatifs à : [C] gestion des nombres aléatoires


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR