[C] gestion des nombres aléatoires

gestion des nombres aléatoires [C] - C++ - Programmation

Marsh Posté le 01-06-2003 à 11:43:54    

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 -> Google Pixel 9 PRO XL
Reply

Marsh Posté le 01-06-2003 à 11:43:54   

Reply

Marsh Posté le 01-06-2003 à 11:50:41    

Reply

Marsh Posté le 01-06-2003 à 11:54:31    

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 -> Google Pixel 9 PRO XL
Reply

Marsh Posté le 01-06-2003 à 11:57:11    

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. }

Reply

Marsh Posté le 01-06-2003 à 11:58:54    

:jap: ++Taz


---------------
Samsung Galaxy S1 -> Samsung Galaxy S2 -> Samsung Note 2 -> Huawei Ascend Mate 7 -> ZTE Axon 7 -> OnePlus 6T -> Oppo Find X2 PRO -> Google Pixel 9 PRO XL
Reply

Marsh Posté le 01-06-2003 à 12:04:32    

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

Reply

Marsh Posté le 03-06-2003 à 12:21:33    

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
Reply

Marsh Posté le 03-06-2003 à 12:30:27    

/dev/random

Reply

Marsh Posté le 03-06-2003 à 13:01:10    

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
Reply

Marsh Posté le 03-06-2003 à 13:49:06    

ou une lava lamp

Reply

Marsh Posté le 03-06-2003 à 13:49:06   

Reply

Marsh Posté le 04-06-2003 à 08:04:50    

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 -> Google Pixel 9 PRO XL
Reply

Marsh Posté le 04-06-2003 à 09:44:50    

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
Reply

Marsh Posté le 06-06-2003 à 02:15:25    

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
Reply

Marsh Posté le 06-06-2003 à 10:52:04    

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
Reply

Marsh Posté le 06-06-2003 à 10:55:11    

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

Reply

Marsh Posté le 06-06-2003 à 11:12:28    

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

Reply

Marsh Posté le 06-06-2003 à 11:16:17    

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
Reply

Marsh Posté le 06-06-2003 à 13:06:15    

++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
Reply

Marsh Posté le 06-06-2003 à 13:08:34    

alors autant optimiser son utilisation n'est ce pas

Reply

Marsh Posté le 06-06-2003 à 13:11:26    

++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
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed