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


Sujet :

C

  1. #1
    Rédacteur

    Les nombres aléatoires en C
    http://nicolasj.developpez.com/artic...s/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
    Citation Envoyé par gege2061 Voir le message
    http://nicolasj.developpez.com/artic...s/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

    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
    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
    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)
    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
    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
    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é
    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
    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é
    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
    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é
    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
    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é
    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)
    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é
    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
    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é
    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)
    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.