JeuWeb - Crée ton jeu par navigateur
rand VS mt_rand? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : rand VS mt_rand? (/showthread.php?tid=5390)



rand VS mt_rand? - Argorate - 28-04-2011

Bonjour à vous,

suite à un débat initié dans le burreau au sein du quel je travail, j'ai décider d'ouvrir le débat ici, et histoire d'etre constructif, j'ai effectué qulques tests.

Si on s'en tien a la documentation : http://php.net/manual/fr/function.mt-rand.php

mt_rand() est meilleure car plus aléatoire et 4x plus rapide (ce qui est non négligeable).
Malheureusement... il semblerait qu'on nous ait menti! Où du moins, a moitié, mt_rand() semble plus lent que rand() mais a un taux d'erreur moins élevé, donc génére mieux l'aléatoire.

C'est la conclusion que j'en ai tirer après avoir répété le test plusieurs fois (effectuer sur 1 million de boucle chacun):

Citation :rand(1, 100) à mis 6.7577540874481 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.001417 - 0.1417% (1417)

mt_rand(1, 100) à mis 6.9153845310211 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.008029 - 0.8029% (8029)

rand(1, 10000) à mis 6.8464136123657 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.122217 - 12.2217% (122217)

mt_rand(1, 10000) à mis 7.1655714511871 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.080141 - 8.0141% (80141)

Donc plus long, mais plus aléatoire, après faut faire sont choix.
Cependant on peut améliorer (quelque soit la fonction utilisé) la valeur de l'aléatorie en baissant le taux d'erreurs via les fonction srand() et mt_srand() qui initialise le générateur d'aléatoire.

Voilà ce que ça donne avec les générateurs pour les deux fonctions:

Citation :Générateur initialisé

rand(1, 100) à mis 6.8553650379181 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.001395 - 0.1395% (1395)

mt_rand(1, 100) à mis 7.0287108421326 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.008363 - 0.8363% (8363)

rand(1, 10000) à mis 6.9092042446136 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.122185 - 12.2185% (122185)

mt_rand(1, 10000) à mis 7.2302443981171 secondes à s'executer pour 1000000 boucles.
Taux Erreur : 0.078943 - 7.8943% (78943)

On note donc une légère amélioration des résultats grâce à l'initialisation.


Certains se posent sans doute la question, donc je vais y répondre, qu'es ce que j'entends par "taux d'erreur"?

En fait c'est l'écart par rapport à l'équiprobabilité théorique que l'on doit trouver.

Qu'es ce que ça veux dire? Ça veux dire que dans l'absolue, un générateur d'aléatoire, parfait est censé répartir équitablement entre toute les solutions possible (c'est l'équiprobabilité: une probabilité égal entre chaque solution possible).
Autrement dit sur un jet de dé à 6 faces et sur un très grand nombre de lancé, il est censé être sortie le même nombre de fois chaque chiffre de 1 à 6.

Donc pour en revenir a notre fonction, si elle fait X boucle, et un tirage entre 1 et 100 par exemple, on est censé trouvé X/100 tirage pour chaque chiffre entre 1 et 100. Les erreurs sont donc toutes les variations par rapport à ce chiffre théorique.
Autrement dit, pour reprendre l'exemple d'un lancé de dé, si j'obtiens:
98 tirage du 1, 102 du 2, 100 du 3, 99 du 4, 101 du 5 et 100 du 6,
alors si on additionne tout ce qui dépasse la valeur théorique (100 ici), on obtient 6 erreurs.

Pour ce qui veulent, voilà le code que j'utilise pour le test, vous pouvez testé chez vous et me dire si vous en tirez les même conclusion:


<?php
############################################# INITIALISATION #####################################################
set_time_limit(0);
$NB_BOUCLE = 1000000;
$INI=true;
if($INI)
{
echo 'Générateur initialisé<br/><br/>';
mt_srand(round(microtime(true)));
srand(round(microtime(true)));
}

############################################# PROGRAMME PRINCIPAL #####################################################
executeTest('rand', 100, $NB_BOUCLE);
executeTest('mt_rand', 100, $NB_BOUCLE);

executeTest('rand', 10000, $NB_BOUCLE);
executeTest('mt_rand', 10000, $NB_BOUCLE);

############################################# FONCTIONS #####################################################
//remplit le compteur $tab avec les resultat des random
//@return : temps d'exec du random
function doRandom(&$tab, $func, $max, $NB_BOUCLE)
{
$time_total=0;
for ($i = 1; $i < $NB_BOUCLE; ++$i)
{
$time = microtime(true);
$tab[$func(1, $max)]++;
$time_total += microtime(true) - $time;
}
return $time_total;
}

//execute x fois le test de la fonction random passé en parametre (mt_rand ou rand)
//Affiche le temps d'exec et le taux d'erreur
function executeTest($func, $max, $NB_BOUCLE)
{
$tab=array();
$temps_exec = doRandom($tab, $func, $max, $NB_BOUCLE);

$erreur=0;
foreach($tab as $rand => $nb) $erreur += abs($nb - ($NB_BOUCLE/$max));
echo $func.'(1, '.$max.') à mis '.$temps_exec.' secondes à s\'executer pour '.$NB_BOUCLE.' boucles.<br />Taux Erreur : '.($erreur/$NB_BOUCLE).' - '.($erreur*100/$NB_BOUCLE).'% ('.$erreur.')<br/><br/>';
}
?>

Voilà, qu'en pensez vous?
De base j'utilise mt_rand() et sans initialisé le générateur (je ne connaissais pas trop ce procédé)
Qu'utilisez vous?


RE: rand VS mt_rand? - srm - 28-04-2011

J'en pense que sur PHP 5.3.6 mt_rand est plus rapide que rand.
mt_rand 1.6047568321228
rand 1.699747800827


RE: rand VS mt_rand? - Argorate - 29-04-2011

J'avoue avoir fait les test sur mon pc de burreau qui a php 5.2.9, je vais voir si je peux pas mettre a jour et relancer le test pour comparer.
EDIT: http://www.wampserver.com/download.php
la dernière version de wamp semble s'arreter à PHP 5.3.5, d'où tu sort la 5.3.6?


RE: rand VS mt_rand? - popayan - 29-04-2011

Est-il vraiment important d'avoir un gain de l'ordre du dixième de sec pour l'affichage d'une page plus ou moins improbable?


RE: rand VS mt_rand? - Argorate - 29-04-2011

C'est pas vraiment le gain pur le problème, personnellement j'aime bien comprendre le fonctionnement des choses.
Après je suis un peu perfectionniste sur les bords, donc même si je gagne pas beaucoup, c'est pour le principe d'utiliser la méthode optimisé... car c'est toujours pareil : 0.01seconde par ci + 0.01 seconde par là et au final tu peux gagner bien plus pour des efforts moindre.
Mais c'était aussi et avant tout pour partager le fait que ce n'est pas "4x plus rapide" comme l'indique la doc, mais que cependant l'algo génère du "meilleur aléatoire". Wink


RE: rand VS mt_rand? - Sephi-Chan - 29-04-2011

Mais la méthode recommandée, d'après la documentation, c'est mt_rand. Et la doc a mille fois plus de valeur que n'importe quel benchmark puisque les chiffres varient énormément d'une machine à l'autre, d'une version à l'autre, etc.

Je doute que leur "4 fois plus rapide" est pertinent, mais c'est peut-être l'algorithme qui est 4 fois moins complexe (avec les notation en O).

Rappelle toi que tu pourras gagner toutes les millisecondes que tu veux, ça sera compensée par un accès aux données mal caché et compagnie, et en un appel à la base de données supplémentaire 1 fois dans la journée, tu perds le bénéfice de ces pathétiques micro-optimisations.

Moralité : utilise plutôt ton temps pour apprendre à utiliser Memcache, Redis, APC, etc. que sur ce genre de conneries.


Sephi-Chan


RE: rand VS mt_rand? - Argorate - 29-04-2011

Je sais que ça ne te passionne pas, mais je trouve intéressant, surtout dans le cadre de créateur de jeu que nous somme, de savoir que le hasard que l'on produit est de meilleure qualité dans le cas de mt_rand().
Franchement quel jeu "complexe" n'utilise pas de random? C'est quand même assez important je trouve, pour l'équilibre et le fair play du jeu.
L'historie des milliseconde c'est juste un bonus, et encore, je suis prêt les perdre si ça m'assure un meilleur tirage aléatoire, donc ce n'est pas vraiment le problème ici^^


RE: rand VS mt_rand? - Sephi-Chan - 29-04-2011

Donc si je résume :
  • mt_rand() est la méthode recommandée par PHP à la place de rand() ;
  • mt_rand() fournit un aléatoire plus sûr que rand() ;
  • mt_rand() est donnée plus rapide que rand() (bien que ça varie selon les benchmarks) ;

Du coup… Pourquoi on en parle ? :heu:

Je comprends que tu manques de temps à en perdre sur ce genre de questions… Tout était déjà dit dans la documentation.


Sephi-Chan