Partage
  • Partager sur Facebook
  • Partager sur Twitter

Mon programme aléatoire ne fait pas d'aléatoire

    8 novembre 2023 à 17:41:57

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

    /*La fonction aleaInfBorne génère un nombre entier aléatoire compris entre 0 et
    une borne supérieure donnée en paramètre.*/

    int aleaInfBorne(int borne);

    int main() {
        int borne =20000;//Borne supérieure de l'intervalle de nombres aléatoires
        int nbAleatoire = aleaInfBorne(borne);
        printf("Le nombre aleatoire genere est : %d\n", nbAleatoire);
        return EXIT_SUCCESS;
    }

    int aleaInfBorne(int borne){
        srand(time(NULL));
        return rand() % borne;
    }
    voici mon code c'est sensé renvoyer un nombre aléatoire en 0 et 20000(la borne) mais après plusieurs exécutions,
    les valeurs renvoyés ne sont en aucun cas aléatoire. Auriez vous la réponse ? merci d'avance.
    • Partager sur Facebook
    • Partager sur Twitter
      8 novembre 2023 à 18:10:02

      Hello,

      D'abord, srand() ne s'appelle qu'une seule fois, en début du main() par exemple, et on ne voit pas les résultats de tes exécutions.

      Ensuite, si tu exécutes ton programme plusieurs fois durant la même seconde, le srand() recevra toujours la même valeur (puisque la valeur renvoyée par time() ne change que toutes les secondes) et donc le rand() génèrera la même valeur.

      Enfin,

      -
      Edité par edgarjacobs 8 novembre 2023 à 18:14:59

      • Partager sur Facebook
      • Partager sur Twitter

      On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

        10 novembre 2023 à 10:56:15

        Effectivement, srand() ne devrait être exécuté qu'une fois par le programme ou en tout cas n'a pas vocation à être intégré dans une boucle ou une fonction appelée par une boucle pour les raisons expliquées.

        Le problème demeure que si le programme doit être exécuté (l'exécutable du programme lancé) plusieurs fois dans un intervalle de temps rapide inférieur à 1 seconde, l'instruction srand(time(NULL)); sera initialisée avec la même graine produite par time(NULL) pour toutes les exécutions faites dans la même seconde, et le résultat de srand() sera identique pendant cette seconde.

        Si on a vraiment besoin de faire cela, on pourrait utiliser une autre graine dont on aurait l'assurance qu'elle soit différente à chaque exécution même si le programme est exécuté plusieurs fois dans la même seconde.

        Cela peut être un timer avec une plus grande résolution que la seconde, ou le process ID du programme ou n'importe quoi d'unique au programme lancé que l'on puisse exprimer ou transformer sous la forme d'un unsigned int attendu par srand().

        Le désavantage de ne pas utiliser time(NULL) pour générer la graine est que l'on doit utiliser des fonctions non standard du C, particulières au système utilisé, mais on peut tout à fait utiliser autre chose.

        Exemple donné sur un post récent sur un autre forum :

        https://www.developpez.net/forums/d2158198/c-cpp/c/debuter/probleme-generation-aleatoire/#post11983230

        qui fonctionne sous Linux avec getpid() (qui renvoie un pid_t, qui se trouve être implémenté comme un alias sur unsigned int sous Linux).

        L'opération bitwise XOR proposée par le contributeur de ce forum n'est pas vraiment nécessaire si, se toutes façons, la graine n'est initialisée qu'une fois pour un processus donné, et on pourrait se contenter de srand(getpid()).

        https://linux.die.net/man/2/getpid

        -
        Edité par Dlks 10 novembre 2023 à 11:04:34

        • Partager sur Facebook
        • Partager sur Twitter
          10 novembre 2023 à 18:36:39

          @Dlks: j'avais déjà lu cette discussion, et j'avais testé sous windows

          #include <time.h>
          #include <stdio.h>
          #include <stdlib.h>
          #include <process.h>		// pour _getpid()
          
          #define XOR ^			  // pour faciliter la lecture aux débutants
          
          int main(void) {
              srand(time(NULL) XOR _getpid());
              printf("%d\n", rand());
              return(0);
          }
          

          lancé avec le .bat

          @echo off
          :next
          rand
          goto next
          

          et, évidemment, ça fonctionnne. Mais je ne mettrais pas que le _getpid(), ne pourrait-il pas se répéter ? (aucune expérience à ce sujet) (mais ce n'est sans doute qu'une question théorique).

          -
          Edité par edgarjacobs 10 novembre 2023 à 18:57:40

          • Partager sur Facebook
          • Partager sur Twitter

          On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

            10 novembre 2023 à 19:02:47

            edgarjacobs a écrit:

            (...) ça fonctionnne. Mais je ne mettrais pas que le _getpid(), ne pourrait-il pas se répéter ? (aucune expérience à ce sujet).

            Le problème que l'on cherche à résoudre est que si l'exécutable est lancé à intervalles très rapprochés inférieurs à 1 seconde, srand(time(NULL)) est initialisé avec la même graine et rand() produit le même résultat.

            Le fait de conserver time(NULL) dans la détermination de la graine ne nous aide donc pas.

            En revanche, comme dans un système d'exploitation l'ID du processus doit être unique, par définition, c'est le seul élément réellement utile dans ce code pour résoudre notre problème.

            C'est intéressant de savoir que la fonction POSIX getpid() est implémentée sous la forme de _getpid() (qu'on ne peut pas utiliser pour des applications UWP cependant). Bizarrement elle retourne un int (un entier signé...) :

            https://learn.microsoft.com/fr-fr/cpp/c-runtime-library/reference/getpid?view=msvc-170

            Un programmeur Windows, je pense, utiliserait plutôt GetCurrentProcessId() :

            https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid

            qui retourne un "DWORD" qui, pour Microsoft, est un typedef sur un type unsigned long int.

            https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/262627d8-3418-4627-9218-4ffe110850b2

            Microsoft fait un tour de passe-passe et n'explique pas sa doc comment un DWORD peut finalement être exprimé comme un int.

            Cela nous arrange dans le cas de l'utilisation avec srand() (car la graine doit être un unsigned int selon le standard, à condition que Microsoft ne renvoie pas des entiers négatifs)... mais c'est une absurdité et contradiction parmi d'autres dans ce que nous propose ce système.

            J'aurai plutôt eu tendance, sous Windows, à utiliser GetCurrentProcessId() et hacher le DWORD sous la forme de quelque chose tenant dans un unsigned int.

            -
            Edité par Dlks 10 novembre 2023 à 19:17:14

            • Partager sur Facebook
            • Partager sur Twitter
              10 novembre 2023 à 20:00:16

              Dlks a écrit:

              Le fait de conserver time(NULL) dans la détermination de la graine ne nous aide donc pas --> 1

              qui retourne un "DWORD" qui, pour Microsoft, est un typedef sur un type unsigned long int --> 2

              1) exact, j'ai répondu sans réfléchir

              2) la doc ms se prend les pieds me semble-t-il: DWORD Ça parle d'unsigned int, mais aussi d'un typedef unsigned long, ce qui est différent (sauf si sizeof(int)==sizeof(long))*, et je n'arrive pas à trouver le .h où se trouve le typedef


              *après vérification, c'est le cas

              -
              Edité par edgarjacobs 10 novembre 2023 à 23:04:10

              • Partager sur Facebook
              • Partager sur Twitter

              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

              Mon programme aléatoire ne fait pas d'aléatoire

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              • Editeur
              • Markdown