IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Les nombres aléatoires en C [Tutoriel]


Sujet :

C

  1. #1
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Points : 11 625
    Points
    11 625
    Par défaut Les nombres aléatoires en C
    http://nicolasj.developpez.com/articles/libc/hasard/

    Au travers de ce tutoriel, je vais vous exposer différentes méthodes pour générer une suite de nombres pseudo-aléatoires. La théorie peut s'appliquer à tous les langages de programmation. Par contre les exemples seront donnés en C.
    Vous pouvez laisser un commentaire sur cet article à la suite.

  2. #2
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par gege2061 Voir le message
    http://nicolasj.developpez.com/articles/libc/hasard/.

    IV. Mettons-y notre grain de sable
    Je ne suis pas du tout d'accord avec cette méthode.

    Que se passe-t-il si il y a plusieurs processus ?

    Et si il y a une autre fonction de génération avec sa propre logique ? Elle va avoir le même mécanisme et réinitialiser elle aussi la graine, sans prévenir ?

    D'une manière générale, les statiques, c'est NON.

    La méthode est connue : Un appel systématique à srand() au début du code (main(), avant toute boucle) et c'est tout.

    Si il y a plusieurs processus, à renouveler à chaque démarrage de processus (fork() etc.). En principe, c'est automatique si srand() est bien placé.
    Pas de Wi-Fi à la maison : CPL

  3. #3
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Points : 11 625
    Points
    11 625
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Je ne suis pas du tout d'accord avec cette méthode.

    Que se passe-t-il si il y a plusieurs processus ?

    Et si il y a une autre fonction de génération avec sa propre logique ? Elle va avoir le même mécanisme et réinitialiser elle aussi la graine, sans prévenir ?

    D'une manière générale, les statiques, c'est NON.

    La méthode est connue : Un appel systématique à srand() au début du code (main(), avant toute boucle) et c'est tout.

    Si il y a plusieurs processus, à renouveler à chaque démarrage de processus (fork() etc.). En principe, c'est automatique si srand() est bien placé.
    Il s'agit d'un tutoriel pour débutant, comme pour les autres, il y a forcement un choix à faire entre être accessible à tous et satisfaire des exigences de développeurs industriels...

    Même la norme C n'impose pas ce genre de chose : avec l'exemple du paragraphe 7.20.2.2 (n1256) peux importe que j'utilise une variable statique...

    Quand j'aurais le temps je rajouterai une note sur la bonne utilisation de srand, en attendant ton commentaires servira d'erratum.


  4. #4
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par gege2061 Voir le message
    Il s'agit d'un tutoriel pour débutant,
    Justement. Éviter les mauvaises pratiques me semble une priorité. Il y va aussi de la réputation de sérieux du site...
    Pas de Wi-Fi à la maison : CPL

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Août 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 99
    Points : 62
    Points
    62
    Par défaut a propos de la mise a echelle
    Salut,

    Je ne comprends pas bien cette partie :
    Nous obtenons plus de nombres compris entre 0 et 5, pour pallier ce problème, il faut réaliser une "mise à l'échelle" (extrait de la faq FAQ C) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #include <stdlib.h>
     
    int randomValue = (int)(rand() / (double)RAND_MAX * (N - 1));
    si on prend comme dans l'exemple RAND_MAX = 25 et N = 10, on se retrouve avec les possiblités suivantes :
    25 / 25 * (10-1) = 9
    24 / 25 * (10-1) = 8.64
    23 / 25 * (10-1) = 8.28
    22 / 25 * (10-1) = 7.92
    21 / 25 * (10-1) = 7.56
    20 / 25 * (10-1) = 7.2
    ...
    donc une fois casté on a 9, 8, 8, 7, 7, 7 ...
    On a donc moins de chance d'obtenir un 9 qu'un 7 non?

    ps: je n'ai rien trouvé dans la FAQ pointée au sujet de "mise a l'echelle".

  6. #6
    Invité(e)
    Invité(e)
    Par défaut
    Voici la page dans la FAQ : http://c.developpez.com/faq/?page=al...runif_a_b_reel

    Après, effectivement, il y a quelque chose de louche dans la formule donnée.
    La répartition est bien meilleure avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int randomValue = (int)(rand() / (double)(RAND_MAX-1) * (N));

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Août 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 99
    Points : 62
    Points
    62
    Par défaut
    Merci pour le lien je vais explorer ca. Reste qu'il semble pour le moins difficile d'avoir une repartition totalement egale a partir de rand()

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    La FAQ donne une méthode correcte et un lien vers un document où j'explique comment y arriver et les défauts de quelques méthodes couramment suggérées.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  9. #9
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonsoir,

    dans une future version, il pourrait être intéressant d'introduire d'autres choses :

    • les notions d'indépendance, de discrépance,
    • les outils pour évaluer son générateur (test du chi^2,...)
    • un algo moderne (Mersenne Twister,...).

  10. #10
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    Bonsoir,

    dans une future version, il pourrait être intéressant d'introduire d'autres choses :

    • les notions d'indépendance, de discrépance,
    • les outils pour évaluer son générateur (test du chi^2,...)
    • un algo moderne (Mersenne Twister,...).
    Dans un cours de math et non de C alors ...

  11. #11
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Citation Envoyé par Melem Voir le message
    Dans un cours de math et non de C alors ...
    Désolé, j'ai cru qu'il s'agissait d'un cours en C et non d'un cours de C.

  12. #12
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    Désolé, j'ai cru qu'il s'agissait d'un cours en C et non d'un cours de C.
    C'est plutôt les deux en même temps. Le but de l'article est clairement deux présenter deux seules fonctions standard de manipulation de nombres aléatoires en C, rand et srand, à savoir comment les utiliser correctement et comment sont-elles implémentées. En effet, la compréhension de leur fonctionnement interne ne peut qu'aider à mieux les utiliser. Dans ce sens, je trouve difficilement envisageable d'ajouter quoi que ce soit d'autre à ce tuto qui est déjà complet, sans remettre en cause l'intérêt d'un second tuto cette fois-ci plus axé sur les maths.

  13. #13
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonsoir,

    Citation Envoyé par Melem Voir le message
    En effet, la compréhension de leur fonctionnement interne ne peut qu'aider à mieux les utiliser.
    Est-ce que vous avez compris quand il ne faut surtout pas les utiliser?

  14. #14
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    Est-ce que vous avez compris quand il ne faut surtout pas les utiliser?
    Oui j'ai bien compris. Et vous ?

  15. #15
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    Citation Envoyé par Melem Voir le message
    Oui j'ai bien compris. Et vous ?
    En ce qui me concerne, pas du tout.
    Une mise en garde aborde très succintement la notion de période mais ce terme n'est même pas utilisé :
    Testons :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    455
    231
    231
    231
    231
    ...
    C'est plutôt prévisible pour une suite de nombres aléatoires ! Un sujet aussi complexe que le hasard ne peut être résumé par une formule aussi simple. Il existe des contraintes dans le choix des différents paramètres pour éviter ce genre de problème (ce qui, ici, se détecte facilement mais est parfois plus difficilement décelable car visible uniquement pour des valeurs précises de X) :


    • b et c ne doivent pas être multiple l'un de l'autre
    • a-1 doit être un multiple de n, avec n tous les nombres premiers diviseurs de c
    • Si c est multiple de 4, a-1 doit être un multiple de 4
    Même si ces conditions sont réunies, il peut subsister des erreurs, ou plutôt des imperfections au niveau du caractère aléatoire des nombres. Par exemple, si c est une puissance de 2, le bit de poids faible des nombres oscillera successivement entre 0 et 1. De même pour le générateur UNIX :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Xn+1 = ( 1103515245 * xn + 12345 ) % 2147483647
    Même si ce générateur fonctionne correctement, il faut tout de même faire attention : les octets de poids faibles ne sont pas réellement aléatoires.

  16. #16
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    J'ai fait un petit test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void TestRand(void)
    {
      float N;
      int Tab[10];
      for (int i=0; i<10; i++) Tab[i]=0;
      for (int i=0; i<100; i++)
      {
        N=(float)10.0*rand()/RAND_MAX;
        for (int j=9; j>=0; j--)
        {
          if (N>(float)j) {Tab[j]++; break;}
        }
      }
      for (int i=0; i<10; i++)
      {
        printf("rang %d  %d valeurs\n",i+1,Tab[i]);
      }
    }
    C'est à dire que je calcule 100 valeurs aléatoires flottantes entre 0 et 10 et je compte les résultats.
    Le résultat global me parait correct, si on calcule 1000 valeurs, le résultat me parait excellent.

    Par ailleurs, je ne comprend pas où il serait question de "manipulation" de nombre aléatoire, il s'agit juste de générer des nombres aléatoires.
    Naturellement il est bon d'initialiser le générateur par un appel à randomize().

  17. #17
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Naturellement il est bon d'initialiser le générateur par un appel à randomize().
    Tu voulais certainement dire srand().
    To start press any key. (reading screen) Where's the "any" key? I see Esc, Catarl, and Pig Up. There doesn't seem to be any "any" key. Wo! All this computer hacking is making me thirsty. I think I'll order a Tab. (presses TAB key). -- HOMER --

  18. #18
    Expert éminent
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Points : 8 389
    Points
    8 389
    Par défaut
    Aleph69 : On voit bien que la valeur 231 se répète sans arrêt là. Faut-il vraiment une phrase où le radical "période" est présent pour que le lecteur le comprenne ? Personnellement, je trouve le commentaire du tutoriel on ne peut plus clair.

    Pierre : Et bin remplace le mot manipulation par génération si ça peut t'aider à ieux comprendre .

  19. #19
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Melem,

    je suis très surpris des propos que vous tenez.
    Pour le moment, l'intérêt d'en discuter avec vous me semble limité car il est évident que vous ne comprenez pas ce que j'écris.
    Je ne vous le reproche pas pour autant.
    Par contre, vous devriez vous documenter un minimum sur les générateurs de nombres aléatoires avant de prendre position sur ce sujet.
    J'ai peur que vous défendiez ce tutoriel pour de mauvaises raisons.
    J'espère sincèrement que la rédaction, dont vous faites partie, prendra rapidement en compte les remarques de eilijah et Jean-Marc.Bourguet pour le faire corriger.

  20. #20
    Invité
    Invité(e)
    Par défaut
    Bonjour ssMatio,
    Je parlais effectivement de randomize() qui est utilisable sous Windows.
    srand() est naturellement plus portable, mais il semble nécessaire de l'appeler avec un nombre aléatoire, par exemple l'heure. D'où ma préférence pour randomize() dans l'environnement Windows.
    Dernière modification par Emmanuel Delahaye ; 14/09/2010 à 12h53.

Discussions similaires

  1. les nombres aléatoires en builder
    Par farid0031 dans le forum C++Builder
    Réponses: 5
    Dernier message: 20/11/2009, 20h56
  2. Réponses: 6
    Dernier message: 15/10/2009, 21h18
  3. Etude sur les nombres pseudo-aléatoires
    Par odsen.s dans le forum C
    Réponses: 14
    Dernier message: 21/05/2007, 00h09
  4. [débutant] problème avec les nombres aléatoires
    Par happylife925 dans le forum Débuter
    Réponses: 12
    Dernier message: 10/03/2006, 15h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo