Partage
  • Partager sur Facebook
  • Partager sur Twitter

nombre aléatoire

Sujet résolu
    20 février 2022 à 11:07:59

    Bonjour 🙂

    J'aimerais savoir svp, comment expliquer la construction de la fonction "(rand() % (MAX − MIN + 1)) + MIN; " se trouvant dans l'exemple suivant :

     #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    int main ( )
    {
    int mysteriousNumber = 0, inputNumber = 0;
    const int MAX = 100, MIN = 1;
    // Generation of random number
    srand(time(NULL));
    mysteriousNumber = (rand() % (MAX − MIN + 1)) + MIN;
    
    do
     {
    // We request the number
    printf(”What’s the number? ”);
    scanf(”%d”, &inputNumber );
    // We compare between inputNumber and mysteriousNumber
    if (mysteriousNumber > inputNumber )
    {
    printf(”Greater !\n\n”);
    }
    else if (mysteriousNumber < inputNumber )
    {
    printf(”Lesser !\n\n”);
    }
    else
    {
    printf (”Bravo, you have found the mysterious number !!!\n\n”);
    } while (inputNumber != mysteriousNumber);
    return 0;
    }

    Je vous remercie infiniment 🙏🙏🙏

    • Partager sur Facebook
    • Partager sur Twitter
      20 février 2022 à 11:23:04

      Salut,

      rand() sort un entier pseudo aléatoire entre 0 et RAND_MAX. Il s'agît là de borner le résultat pour réduire cette valeur entre MIN et MAX.

      Bonne continuation.

      • Partager sur Facebook
      • Partager sur Twitter

      Bonhomme !! | Jeu de plateforme : Prototype.

        20 février 2022 à 11:46:24

         Je ne sais pas si ces MIN et MAX aide bien à comprendre ?
        Mais, 
          rand() donne un nombre entier entre 0 et RAND_MAX
          l'opérateur % (modulo) donne le reste de la division entière.  
          donc rand()%100 donne un nombre entre 0 et 99.
          comme tu veux un nombre entre 1 et 100 tu ajoutes donc 1.
        • Partager sur Facebook
        • Partager sur Twitter
        ...
          20 février 2022 à 12:37:14

          Les nombres entiers entre MIN et MAX, il y en a MAX-MIN+1 différents .  Exemple 3 entre 5 et 7.

          Autant que de restes possibles quand on divise par ce nombre.

          • Partager sur Facebook
          • Partager sur Twitter
            20 février 2022 à 19:00:27

            Noter que RAND_MAX vaut 32767
            Si on veut des nombres aléatoires plus grand, c'est moins évident.
            J'ai déjà essayé rand()*rand()
            • Partager sur Facebook
            • Partager sur Twitter

            Le Tout est souvent plus grand que la somme de ses parties.

              20 février 2022 à 19:18:22

              PierrotLeFou a écrit:

              Noter que RAND_MAX vaut 32767
              Si on veut des nombres aléatoires plus grand, c'est moins évident.
              J'ai déjà essayé rand()*rand()


              Ce n'est qu'une garantie de minimum, il peut être différent d'un environnement à l'autre.

              Du coup un autre façon de faire est d'utiliser le fait que (en flottant) 0 ≤ rand()/RAND_MAX ≤ 1 et du coup  min ≤ min + (max-min)*rand()/RAND_MAX ≤ max.

              Une implémentation quick and dirty pourrait donner :

              int rand_between(int min, int max) {
                  return min + (int)( ((double)rand())/RAND_MAX*(max-min) );
              }



              • Partager sur Facebook
              • Partager sur Twitter
                21 février 2022 à 3:54:21

                Effectivement, on peut obtenir des nombres aléatoires dans l'intervalle qu'on désire. Mais on n'aura que RAND_MAX valeurs différentes.
                L'étalement est plus grand, mais la densité diminue.
                En prenant ((double)rand()*rand() / (RAND_MAX*RAND_MAX))
                on obtient une densité plus forte, donc plus de nombres différents.
                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  21 février 2022 à 4:41:44

                  Je ne suis pas sûr que le produit conduise à une distribution uniforme.

                  Le produit de 2 nombres modulo n est entre 0 et (n-1)^2,  et 0 est obtenu de  2n-1 façons différentes.

                  A la place, je construirai plutôt un grand nombre aléatoire par juxtaposition de "tranches de bits" (moins de 15 a la fois, puisque limitation a 32K)

                  • Partager sur Facebook
                  • Partager sur Twitter
                    21 février 2022 à 7:09:59

                    > Je ne suis pas sûr que le produit conduise à une distribution uniforme.
                    Moi non plus ...
                    Si on veut utiliser les long long, il y a fort à parier qu'on pourrait trouver un nombre premier de l'ordre de 2^42 et un multiplicateur de l'ordre de 2^14 à 2^21
                    (par ex. 4398046511093)
                    Pour une fonction random à modulo tel que  s' = s * m % p
                    où p est un nombre premier et m est un multiplicateur et s est la semence suivante.
                    et tels qu'on retourne à la semence initiale en p-1 itérations.
                    Je n'ai pas essayé de trouver le multiplicateur ...  2^42 nano-secondes, ça risque d'être long.

                    Edit: c'est pour tester un seul multiplicateur (et je suis optimiste dans mes évaluations)
                    Bah, à peine 4096 secondes ...

                    Voici des valeurs plus modestes:
                    long long p = 3037000493;
                    long long m = 28276;

                    -
                    Edité par PierrotLeFou 21 février 2022 à 7:22:04

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Le Tout est souvent plus grand que la somme de ses parties.

                      21 février 2022 à 10:45:56

                      Après m'être rendormi et réveillé, j'ai pondu le code pour une fonction qui fabrique un nombre aléatoire long par tranches (de 8 bits)

                      #include <stdio.h>
                      #include <stdlib.h>
                      #include <time.h>
                      
                      unsigned long long ull_rand(void)
                      {
                          union {
                              unsigned long long number;
                              char bytes[sizeof(unsigned long long)];
                          } u;
                      
                          for (size_t i = 0; i < sizeof(unsigned long long); i++) {
                              u.bytes[i] = rand();
                          }
                          return u.number;
                      }
                      
                      int main()
                      {
                          // initialiser le générateur
                          srand(time(NULL));
                      
                          printf("# Génération aléatoire de nombres entiers longs :"
                                 " unsigned long long\n");
                          for(int i = 0; i < 10; i++) {
                              printf("%20llx\n", ull_rand());
                          }
                      }


                      Résultat, avec affichage en hexa, pour qu'on voie bien que les octets changent d'un appel à l'autre

                      # Génération aléatoire de nombres entiers longs : unsigned long long
                           798d08843962d12
                          fda99fd08c658cce
                          23a4caae3121f185
                          a0bc368e89ffbcdb
                          f1f37c23ece45263
                          7dd626f7d97d5809
                          9de952c2c6aef818
                          823de31f9c27e90e
                          a64a619d596e2136
                           52e56edb180c7b9
                      


                      Pour ce qui est de la distribution dans le cas de rand()*rand(), j'ai réfléchi. L'effet principal c'est que je me suis rendormi, mais accessoirement :

                      • la seule façon de retourner 1, c'est d'obtenir deux tirages à 1 consécutifs
                      • par contre il y a 64000 façons d'obtenir 0
                      • un nombre premier s'obtient de deux façons, si il est plus petit que 32K. Aucune sinon.
                      • un nombre de la forme  p^k (avec p premier) s'obtient à peu près de k+1 façons différentes si il est plus petit que 32K
                      Exemple 2^4 = 16 = 1*16 ou 2*8 ou 4*4 ou 8*2 ou 15*1

                      -
                      Edité par michelbillaud 21 février 2022 à 10:46:31

                      • Partager sur Facebook
                      • Partager sur Twitter
                        21 février 2022 à 10:57:36

                        «Anyone who attempts to generate random numbers by deterministic means is, of course, living in a state of sin.»
                        John von Neumann.

                        Les plateformes modernes proposent en général un accès à un «vrai» rng si le besoin s'en fait ressentir. Maintenant il y a une tonne de littérature qui explique comment créer un prng avec des propriétés précises.

                        • Partager sur Facebook
                        • Partager sur Twitter
                          21 février 2022 à 11:41:43

                          est-ce que rand() y fait appel ?
                          • Partager sur Facebook
                          • Partager sur Twitter
                            21 février 2022 à 13:31:40

                            Quel rand() ? sur quelle plateforme ? quel environnement ? quelles options de compilations de la libc ?
                            Il n'y a même pas de contraintes dans la norme sur ce que rand() doit réellement fournir … on y lit même en footnote : «There are no guarantees as to the quality of the random sequence produced and some implementations are known to produce sequences with distressingly non-random low-order bits. Applications with particular requirements should use a generator that is known to be sufficient for their needs.»

                            On n'est même pas obligé de passer par rand(), par exemple sous linux il y a les /dev/random et /dev/urandom … les systèmes POSIX proposent d'autres interfaces …

                            Si on a des besoins spécifiques il faut généralement faire appel à autre chose que rand() qui est a priori même limite pour un fisher yates sur un jeu de cartes (si on pousse le bouchon).

                            • Partager sur Facebook
                            • Partager sur Twitter
                              21 février 2022 à 13:43:25

                              Est-ce que "Guess a number" est un besoin spécifique ?  :-=

                              • Partager sur Facebook
                              • Partager sur Twitter
                                21 février 2022 à 14:33:35

                                C'était plus dans le sens que la discussion prenait entre toi et Pierrot, à dire le besoin spécifique de dépasser le minimum normatif de la norme. Je ne me serais pas permis d'intervenir ainsi pour un simple guess my number.

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  21 février 2022 à 15:56:27

                                  Si j'ai bien compris, je m'achête une série de compteurs 8 bits que je monte en séquence avec un oscillateur qui pousse le circuit à la limite.
                                  Il faut ensuite juste écrire le driver et espérer que l'ordi pourra y accéder ...
                                  Petite note sur rand()
                                  Si je prend une semence et que j'appelle rand() jusqu'à ce que je retrouve cette première semence, je n'ai jamais le même nombre d'ittérations.

                                  Avec un générateur à modulo avec p=65537 et m=75, j'ai un cycle de 65536 itérations.

                                  -
                                  Edité par PierrotLeFou 21 février 2022 à 16:00:48

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Le Tout est souvent plus grand que la somme de ses parties.

                                    21 février 2022 à 16:03:28

                                    ou si tu en as besoin tu utilises RDRAND/RDSEED sur les x86 pas trop anciens ;

                                    ou des bibliothèques qui proposent des prng avec des propriétés précises ;

                                    ou tu regardes ce que ton OS propose ;

                                    Edit:

                                    PierrotLeFou a écrit:

                                    [...]
                                    Avec un générateur à modulo avec p=65537 et m=75, j'ai un cycle de 65536 itérations.

                                    -
                                    Edité par PierrotLeFou il y a 2 minutes


                                    Ce qui est insuffisant pour avoir un fisher yates sur un tableau de 9 éléments ou plus qui donnerait toutes les permutations suivant une loi uniforme.

                                    -
                                    Edité par White Crow 21 février 2022 à 16:06:12

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      21 février 2022 à 17:19:27

                                      Le code de michel, m'a fait penser à BCryptGenRandom de Windows qui rempli un buffer :

                                      #include <stdio.h>
                                      #include <windows.h>
                                      #include <bcrypt.h>
                                      
                                      int main(void)
                                      {
                                          union
                                          {
                                              unsigned long long number;
                                              BYTE bytes[sizeof(unsigned long long)];
                                          } u;
                                      
                                          for(size_t j=0; j<20; j++)
                                          {
                                              BCryptGenRandom(NULL, u.bytes, sizeof(unsigned long long),
                                                                                     BCRYPT_USE_SYSTEM_PREFERRED_RNG);
                                              printf("\n%24llu",u.number );
                                          }
                                          printf("\n");
                                      
                                          return 0;
                                      }



                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      ...
                                        21 février 2022 à 18:54:52

                                        White Crow a écrit:
                                        > Ce qui est insuffisant pour avoir un fisher yates sur un tableau de 9 éléments ou plus qui donnerait toutes les permutations suivant une loi uniforme.
                                        Je n'ai pas mentionné qu'on retourne s-1 au programme. Donc 0 <= s-1 < p-1
                                        Si j'utilisais ton truc:
                                        (double)(s-1)/(p-1) * longueur_de_l'intervalle avec un nombre p assez grand, est-ce que ça serait mieux?

                                        L'intervalle des nombres réels est infiniment dense, mais ça n'est pas possible d'avoir ça dans un ordi.

                                        -
                                        Edité par PierrotLeFou 21 février 2022 à 18:57:56

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Le Tout est souvent plus grand que la somme de ses parties.

                                          21 février 2022 à 19:30:05

                                          rouIoude a écrit:

                                          Le code de michel, m'a fait penser à BCryptGenRandom de Windows qui rempli un buffer :

                                          comme quoi

                                          • c'est difficile d'être original (*)
                                          • j'ai peut être un jumeau (malfaisant) chez microsoft du mauvais côté de la force
                                          Ca me fait penser à un truc revu ce matin par hasard, la seule fâcherie entre Thomson et Ritchie (ou Kernighan ?, je sais plus) : ils avaient écrit tous les deux un code assembleur absolument identique, aux commentaires près. La fâcherie, c'est pas d'avoir écrit le même code, mais de ne pas s'être coordonnés qui aurait évité de le faire deux fois.

                                          (*) L'alternative pour l'union, c'était un bidouillage avec adresse/transtypage/indirection.
                                          unsigned long long ull_rand(void)
                                          {
                                              char bytes[sizeof(unsigned long long)];
                                           
                                              for (size_t i = 0; i < sizeof(unsigned long long); i++) {
                                                  bytes[i] = rand();
                                              }
                                              return * (unsigned long long *) bytes;
                                          }
                                          

                                          J'aime moins, mais du coup j'ai vérifié : le compilo gcc en fait exactement la même chose (-O3 -S).
                                          PS en fait ça me revient, ma première idée - avant les "tranches" était de faire par décalage, à la manière des "n = 10 * n + d" des conversions en décimal
                                          unsigned long long r = 0;
                                          
                                          for (.....) {
                                              r = (r << 15) ^ rand();   // xor, plus, or ?
                                          }
                                          
                                          return r;
                                          
                                          mais bon...

                                          -
                                          Edité par michelbillaud 21 février 2022 à 19:52:05

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            21 février 2022 à 21:43:37

                                            PierrotLeFou a écrit:

                                            White Crow a écrit:
                                            > Ce qui est insuffisant pour avoir un fisher yates sur un tableau de 9 éléments ou plus qui donnerait toutes les permutations suivant une loi uniforme.
                                            Je n'ai pas mentionné qu'on retourne s-1 au programme. Donc 0 <= s-1 < p-1
                                            Si j'utilisais ton truc:
                                            (double)(s-1)/(p-1) * longueur_de_l'intervalle avec un nombre p assez grand, est-ce que ça serait mieux?

                                            L'intervalle des nombres réels est infiniment dense, mais ça n'est pas possible d'avoir ça dans un ordi.

                                            -
                                            Edité par PierrotLeFou il y a environ 1 heure


                                            Ah ben non, ça n'aurait pas été mieux … 

                                            Si tu veux pouvoir choisir au hasard (en suivant une loi uniforme) une des n! permutations de ⟦0, n-1⟧ il te faut au moins un prng dont le cycle est supérieur à log2(n!). Dans l'exemple dont je poussais le bouchon un peu loin, un fisher yates sur un jeu de 52 cartes il te faut au moins log2(52!) = 225.8 ⇒ 226 bits.

                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            nombre aléatoire

                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                            • Editeur
                                            • Markdown