Accueil > Développement > Programmation > Génération de nombres aléatoires

Génération de nombres aléatoires

Du chaos naîtra un ordre, peut-être même des ordres !

lundi 7 août 2006, par Prélude

Pour commencer, parcequ’il faut bien commncer un jour et par quelque chose, une machine ne sortira jamais réellement un nombre aléatoire au sens propre du terme. Les nombres générés par un programme sont en fait issus d’une suite mathématique.

Une méthode de calcul

Pour exemple simple, nous avons la méthode de Von Neumann qui consiste à prendre un nombre que l’on élève au carré puis, à prendre les chiffres du milieu comme résultat. Ce résultat est utilisé pour le prochain nombre et ainsi de suite.

Un exemple avec de vrais chiffres histoire de comprendre un peu mieux :

On commence avec le nombre suivant : 123
Elevé au carré : 123² = 15129
Donc, nous prenons les chiffres du milieu : 512 (c'est le premier résultat)
Et c'est reparti :
512² = 262144
Donc, nous avons comme résultat : 6214

Au passage, on constate que cette méthode utilise le résultat en terme de chaîne de caractères et non en nombre. Bref...

Il existe évidement beaucoup de méthodes.

La graine

Le nombre de départ est appelé la graine. C’est lui qui va déterminer la suite logique de nombres pseudos aléatoires. Il va donc de soit que ce nombre doit être lui-même aléatoire. Mais là, nous tournons en rond.

Pour sélectionner une graine de "qualité", nous prenons généralement le temps écoulé depuis l’allumage de l’ordinateur.

Et en Php ?

Pour faire simple et aller droit au but qui vous interresse, voici les fonctions vous permettant de générer des nombres aléatoires à partir du Php :

// Initialisation du générateur
srand((float) microtime()*1000000);

// Génération d'un nombre compris entre 1 et 6
$resultat = rand(1, 6) ;

Il s’emblerait d’après la documentation du Php que cette fonction (rand) soit un peu lente. Il existe donc une fonction qui serait plus "rapide" et, en tout cas, meilleure en terme de résultats.

// Initialisation du générateur
mt_srand((float) microtime()*1000000);

// Génération d'un nombre compris entre 1 et 6
$resultat = mt_rand(1, 6) ;

La seule différence est mt_ devant les fonctions.
Bon, d’accord, ce serait plus rapide. Alors testons !

Les tests

Nous avons donc effectuer une boucle de 1 million de générations et regardé en moyenne le temps écoulé :

rand : 1058 ms
mt_rand : 1058 ms

Difficile de dire que l’une est plus rapide que l’autre. Les tests ont été fait sur des serveurs Windows et Linux en Php 4 et 5, avec des valeurs de recherche comprises entre 1 et 6 puis, entre 1 et 6000. Nous retrouvons toujours les mêmes valeurs.

Les suites générées sont très certainement plus "aléatoires" avec la fonction mt_rand. Il est également fort possible que la fonction rand ait été reprogrammée.

Une utilisation particulière

L’aléatoire n’étant pas vraiment aléatoire, il est possible d’utiliser cette possibilité pour effectuer des calculs en fonction d’évènements extérieurs comme par exemple en fonction du jour du mois.

Voici une boucle qui affiche 10 valeurs aléatoires, 5 fois de suite :

for($j=1;$j<=5;$j++) {
srand((float) microtime()*1000000);
        for($i=1;$i<=10;$i++) {
                // Génération d'un nombre compris entre 1 et 6
                $resultat = rand(1, 60000) ;
                echo $resultat.":";
        }
        echo "<br />";
}

Voici le résulat (un des résultats en fait) :

9299:40472:54969:40395:10961:445:15792:18826:33600:26864:
8548:28017:19267:13263:10386:37151:28547:23509:51014:14292:
31035:3183:15109:46568:35950:32619:2386:43602:1372:17407:
51805:55513:38735:27750:52002:5818:55749:41044:4739:2881:
59050:23083:5448:9808:332:16542:31280:9302:53996:19728:

Voici la même boucle, mais en remplaçant l’initialisation du générateur par la ligne suivante :

srand(date("j"));

Le générateur est donc initialisé avec le jour du mois.
Nous avons le résultat suivant :

49653:63:12516:11456:26208:58327:22059:35442:49521:53193:
49653:63:12516:11456:26208:58327:22059:35442:49521:53193:
49653:63:12516:11456:26208:58327:22059:35442:49521:53193:
49653:63:12516:11456:26208:58327:22059:35442:49521:53193:
49653:63:12516:11456:26208:58327:22059:35442:49521:53193:

Vous aurez donc pour un même jour les mêmes résultats.
Ce système peut-être utilisé lorsque vous souhaitez afficher une information aléatoire chaque jour par exemple, mais que cette information soit la même toute la journée.

A vous de compliquez un peu le système pour trouver d’autres utilisations pertinentes.

Messages

  • Merci pour cet article intéressant.

    J’ai quelques compléments à proposer.

    En ce qui concerne la différence entre rand et mt_rand, en dehors des perfs réelles ou supposées, mt_rand permet de générer des nombres aléatoires supérieurs à 32768 sous windows. Ca peut servir ;)

    Ensuite, la possibilité de définir la "graine" est très intéressante. Cela signifie qu’on peut générer une suite toujours identique de nombres aléatoires.

    En fait cela permet d’éviter de stocker certaines infos du jeu. Par exemple pour créer un ensemble d’étoiles positionnées aléatoirement dans un bout d’univers on utilisera une suite de nombres aléatoires générées à partir d’une "graine" qu’on mémorisera.

    Ainsi, il devient inutile de mémoriser la position de chaque étoile, il suffit de mémoriser la "graine". Une simple regénération à partir de celle-ci et on retrouve toutes nos étoiles.

    On perd en temps de calcul ce qu’on gagne en espace disque.

    Je mets en référence l’article sur Gamasutra où j’ai pillé cette idée.

    — 
    Armage

    Voir en ligne : Gamasutra [EN]

  • Juste pour info, il existe une fonction intégrée à PHP, nommée array_rand(), qui permet de tirer une ou plusieurs valeurs au hasard dans un tableau.