Nombres Aléatoires



Avant de commencer, nous allons étudier un point difficile, ce n'est pas à apprendre par cœur, vous pourrez y revenir plus tard mais je tiens quand même à l'expliquer (comme ça le TP est complet).


Ce point important est (comme l'indique le titre), le tirage d'un nombre aléatoire.


En effet, pour notre jeu il va nous falloir tirer un nombre au sort.

Scoop du jour, l'ordinateur ne sait pas faire ça, toutes les informations qu'il nous fournit sont calculées. Le hasard n'existe que dans la nature (et encore ?) et n'a pas de sens en informatique. Alors, pour nous fournir des données aléatoires, l'ordinateur doit simuler le hasard. On parlera alors de données pseudo-aléatoires.

rand()


Pour commencer, n'oubliez pas d'inclure stdlib.h pour pouvoir appeler des fonctions afin de résoudre notre problème.

#include <stdlib.h>


On peut maintenant utiliser la fonction rand qui génère un nombre aléatoire entier et positif !


En réalité, rand renvoie des entiers entre 0 et RAND_MAX, qui est une constante définie dans stdlib.h.


La valeur de RAND_MAX peut varier suivant les compilateurs, mais elle est forcément d'au moins 32767.


Cette fonction ne prend aucun paramètre (donc rien à mettre entre les parenthèses lors de l'appel de la fonction rand).

int main()
{
    int nombre = rand();

    printf("%d", nombre);

    return 0;
}


Je vous laisse exécuter votre programme, moi j'obtiens 41.


41


Maintenant, fermez la console et recommencez l'exécution ! La valeur ne change pas !


Si vous faites une boucle, la valeur changera mais la suite de nombres sera toujours la même !

int main()
{
    int i;

    for (i = 0; i < 3; i++)
        printf("%d\n", rand());

    return 0;
}


En C, on peut appeler rand dans un autre appel (ici, la fonction printf).


Ma console m'affiche donc bien toujours la même suite de nombres...

41

18467

6334


Heureusement, j'ai tout prévu !


                srand()


Les suites de nombres pseudo-aléatoires que peut nous fournir la fonction rand sont calculées à partir d'une donnée seed (graine). Si cette dernière n'est pas modifiée, la suite de nombres sera toujours la même. L'idée est donc d'initialiser cette donnée avec une valeur toujours différente, à chaque démarrage du programme, à l'aide de la fonction srand !

int main()
{
    srand(57); // 57 est la donnée seed
    printf("%d", rand()); // rand  renvoie un nombre calculé à partir de la donnée seed

    return 0;
}


Avec ce code, j'obtiens bien une valeur différente (224) mais elle sera encore toujours la même à chaque exécution du programme puisque la donnée seed ne sera pas initialisée avec une valeur toujours différente.

224


On peut dire que rand et srand communiquent entre eux.


Dites-moi, avec quelle valeur peut-on initialiser la donnée seed ?


Avec la date actuelle !


Ca tombe bien, il existe la fonction time qui renvoie le nombre de secondes entre l'instant où elle est appelée et le 01/01/1970. Pour l'appeler, il faut inclure le fichier d'en-tête time.h.

#include <time.h>


La fonction time renvoie un entier mais nous oblige à lui envoyer un paramètre, on ne va pas s'embêter, on va lui envoyer la valeur NULL (c'est une constante valant 0, que nous verront plus tard).

int main()
{
    srand(time(NULL)); // Initialisation de la donnée seed
    printf("%d", rand()); // rand  renvoie un nombre calculé à partir de la donnée seed

    return 0;
}


Voilà, on aura maintenant toujours une valeur différente ! Ouf !


Mais si je veux une valeur entre 0 et 100 ?


Bonne question ! Nous allons pour ça reprendre quelques points sur le modulo !


Modulo


Vous souvenez-vous du modulo ? L'opérateur arithmétique calculant le reste de la division entière ?


Je vais vous parler uniquement de divisions entières, oubliez le reste.


Voici un exemple d'une division entière.





Le reste est 13 donc 8745 % 37 vaut 13.


printf("8745 %% 37 = %d", 8745 % 37);


On vérifie maintenant le résultat qui nous donne bien 13 :


8745 % 37 = 13


Soit c et x, deux entiers positifs que nous allons utiliser. x sera variable et c sera constant.

Commencez par lire cet exemple bien commenté pour comprendre le modulo :


int main()
{
    int c = 7, x = 2;

    printf("c %% x = %d", c % x);

    /*
    Etape A :
    A = Il y a combien de fois x dans c ?
    A = Il y a combien de fois 2 dans 7 ?
    A = 3

    Etape B :
    B = Il manque combien pour que A multiplié par x soit égal à c ?
    B = a - (A * x)
    B = 7 - (3 * 2)
    B = 1

    Conclusion :
    c % x = 1
    */

    return 0;
}


Le reste de la division de x par c est toujours compris entre 0 et c (exclu). Démontrons cette affirmation !


    * Un reste d'une division est toujours positif et peut être facilement égal à 0.

      Exemple, 5 % 5 vaut 0 puisqu'il y a 5 fois 1 dans 5.


    * c % x ne peut pas être égal à c. Un reste est forcément inférieur au dividende puisqu'une division par 1 ne donne pas de reste.

      Exemple, il y a combien de fois 1 dans 4 ? Le quotient (résultat) est 4 et le reste 0.


En conclusion, on peut dire que par exemple, 482185 % 2812 sera compris entre 0 et 482185 + 1.


Finalisation


Nous voulons maintenant tirer au sort un nombre entre 0 et 100. Il suffit d'utiliser le modulo ! Ce n'est pas pour rien si j'en ai parlé .


int main()
{
    int nombre = 0;
    srand(time(NULL)); // Initialisation de la donnée seed

    nombre = rand() % (100 + 1);
    printf("%d", nombre); // rand  renvoie un nombre calculé à partir de la donnée seed

    return 0;
}


Je n'ai pas oublié d'ajouter 1 pour pouvoir tirer 100 au sort. Si vous avez oublié pourquoi je fais ça, relisez la partie sur le modulo.


Mais moi je veux que ce soit 1 le minimum pas 0 !


Il suffit d'ajouter 1 après l'opération. Comme ça, si on tire au sort 0, 0 + 1 vaut 1, on ne pourra donc pas tomber sur 0


int main()
{
    int nombre = 0;
    srand(time(NULL)); // Initialisation de la donnée seed

    nombre = rand() % (100 + 1);
    nombre += 1;
    printf("%d", nombre); // rand  renvoie un nombre calculé à partir de la donnée seed

    return 0;
}


Oui c'est cool mais on peut tomber sur 101 !


J'attendais cette remarque ! Effectivement on peut tomber sur 101.

Il faut alors retirer 1 dès la première opération avec le modulo, on tire alors au sort un nombre entre 0 et 99 puis on ajoute 1, on a réussi !


int main()
{
    int nombre = 0;
    srand(time(NULL)); // Initialisation de la donnée seed

    nombre = rand() % (100 + 1 - 1);
    nombre += 1;
    printf("%d", nombre); // rand  renvoie un nombre calculé à partir de la donnée seed

    return 0;
}


Pour le code source final, je vais utiliser des entiers constants pour stocker le maximum (MAX) et le minimum (MIN), par exemple, 1 et 100. J'ai raccourci un peu le code source pour le rendre plus clair, il fallait donc faire attention principalement aux priorités des opérations...


int main()
{
    int nombre = 0;
    const int MIN = 1, MAX = 100;
    srand(time(NULL)); // Initialisation de la donnée seed

    nombre = (rand() % (MAX + 1 - MIN)) + MIN; // MIN <= nombre <= MAX
    printf("%d", nombre); // rand  renvoie un nombre calculé à partir de la donnée seed

    return 0;
}


Voilà, on a réussi à tirer au sort un nombre entre 1 et 100, gardez ce code précieusement, il va vous servir pendant la suite de ce TP.


Créé avec HelpNDoc Personal Edition: Créer des fichiers d'aide pour la plateforme Qt Help