PHP 8.4.2 Released!

Random\Randomizer::getFloat

(PHP 8 >= 8.3.0)

Random\Randomizer::getFloatRenvoie un flottant uniformément sélectionné

Description

public Random\Randomizer::getFloat(float $min, float $max, Random\IntervalBoundary $boundary = Random\IntervalBoundary::ClosedOpen): float

Renvoie un flottant uniformément sélectionné et équidistribué d'un intervalle demandé.

A cause de la précision limitée, tous les nombres réels ne peuvent pas être exactement représentés en tant que flottants. Si un nombre ne peut pas être représenté exactement, il est arrondi au nombre exactement représentable le plus proche. De plus, les flottants ne sont pas également denses sur toute la ligne des nombres. Parce que les flottants utilisent un exposant binaire, la distance entre deux flottants voisins double à chaque puissance de deux. En d'autres termes : Il y a le même nombre de flottants représentables entre 1.0 et 2.0 qu'entre 2.0 et 4.0, 4.0 et 8.0, 8.0 et 16.0, et ainsi de suite.

Sélectionner un nombre aléatoire dans un intervalle arbitraire, par exemple en divisant deux entiers, pourrait entraîner une distribution biaisée pour cette raison. L'arrondi nécessaire fera que certains flottants seront retournés plus souvent que d'autres, en particulier autour des puissances de deux lorsque la densité des flottants change.

Random\Randomizer::getFloat() implémente un algorithme qui renverra un flottant uniformément sélectionné à partir de l'ensemble le plus large possible de flottants exactement représentables et équidistribués dans l'intervalle demandé. La distance entre les flottants sélectionnables (« pas ») correspond à la distance entre les flottants avec la plus faible densité, c'est-à-dire la distance entre les flottants aux limites de l'intervalle avec la plus grande valeur absolue. Cela signifie que tous les flottants représentables dans un intervalle donné peuvent ne pas être retournés si l'intervalle traverse une ou plusieurs puissances de deux. Le pas commencera à la limite de l'intervalle avec la plus grande valeur absolue pour garantir que les pas s'alignent avec les flottants exactement représentables.

Les limites d'intervalle fermées seront toujours incluses dans l'ensemble des flottants sélectionnables. Donc si la taille de l'intervalle n'est pas un multiple exact du pas et que la limite avec la plus petite valeur absolue est une limite fermée, la distance entre cette limite et son flottant le plus proche sera plus petite que le pas.

Attention

Le post-traitement des flottants retournés risque de casser l'équidistribution uniforme, car les flottants intermédiaires dans une opération mathématique subissent un arrondi implicite. L'intervalle demandé doit correspondre le plus étroitement possible à l'intervalle souhaité et l'arrondi ne doit être effectué qu'en tant qu'opération explicite juste avant d'afficher le nombre sélectionné à un utilisateur.

Explications de l'algorithme en utilisant des valeurs d'exemple

Pour donner un exemple de fonctionnement de l'algorithme, considérons une représentation en virgule flottante qui utilise une mantisse de 3 bits. Ceci est capable de représenter 8 valeurs flottantes différentes entre les puissances de deux consécutives. Cela signifie qu'entre 1.0 et 2.0 tous les pas de taille 0.125 sont exactement représentables et entre 2.0 et 4.0 tous les pas de taille 0.25 sont exactement représentables. En réalité, les flottants de PHP utilisent une mantisse de 52 bits et peuvent représenter 252 valeurs différentes entre chaque puissance de deux. Cela signifie que

  • 1.0
  • 1.125
  • 1.25
  • 1.375
  • 1.5
  • 1.625
  • 1.75
  • 1.875
  • 2.0
  • 2.25
  • 2.5
  • 2.75
  • 3.0
  • 3.25
  • 3.5
  • 3.75
  • 4.0
sont les flottants exactement représentables entre 1.0 et 4.0.

Maintenant considérons que $randomizer->getFloat(1.625, 2.5, IntervalBoundary::ClosedOpen) est appelé, c'est-à-dire qu'un flottant aléatoire commençant à 1.625 jusqu'à, mais sans inclure, 2.5 est demandé. L'algorithme détermine d'abord le pas à la limite avec la plus grande valeur absolue (2.5). Le pas à cette limite est 0.25.

Il est à noter que la taille de l'intervalle demandé est 0.875, qui n'est pas un multiple exact de 0.25. Si l'algorithme commençait à marcher à la limite inférieure 1.625, il rencontrerait 2.125, qui n'est pas exactement représentable et subirait un arrondi implicite. Donc l'algorithme commence à marcher à la limite supérieure 2.5. Les valeurs sélectionnables sont :

  • 2.25
  • 2.0
  • 1.75
  • 1.625
2.5 n'est pas inclus, car la limite supérieure de l'intervalle demandé est une limite ouverte. 1.625 est inclus, même si sa distance à la valeur la plus proche 1.75 est 0.125, qui est plus petite que le pas déterminé précédemment de 0.25. La raison pour laquelle c'est le cas est que l'intervalle demandé est fermé à la limite inférieure (1.625) et les limites fermées sont toujours incluses.

Finalement l'algorithme sélectionne uniformément une des quatre valeurs sélectionnables au hasard et la renvoie.

Pourquoi diviser deux entiers ne fonctionne pas

Dans l'exemple précédent, il y a huit nombres flottants représentables entre chaque sous-intervalle délimité par une puissance de deux. Pour donner un exemple de pourquoi diviser deux entiers ne fonctionnerait pas bien pour générer un flottant aléatoire, considérons qu'il y a 16 nombres flottants uniformément distribués dans l'intervalle ouvert à droite de 0.0 jusqu'à, mais sans inclure, 1.0. La moitié d'entre eux sont les huit valeurs exactement représentables entre 0.5 et 1.0, l'autre moitié sont les valeurs entre 0.0 et 1.0 avec un pas de 0.0625. Ces valeurs peuvent facilement être générées en divisant un entier aléatoire entre 0 et 15 par 16 pour obtenir l'une des valeurs suivantes :

  • 0.0
  • 0.0625
  • 0.125
  • 0.1875
  • 0.25
  • 0.3125
  • 0.375
  • 0.4375
  • 0.5
  • 0.5625
  • 0.625
  • 0.6875
  • 0.75
  • 0.8125
  • 0.875
  • 0.9375

Ce flottant aléatoire pourrait être mis à l'échelle à l'intervalle ouvert à droite de 1.625 jusqu'à, mais sans inclure, 2.75 en le multipliant par la taille de l'intervalle (0.875) et en ajoutant le minimum 1.625. Cette transformation affine donnerait les valeurs suivantes :

  • 1.625 arrondie à 1.625
  • 1.679 arrondie à 1.625
  • 1.734 arrondie à 1.75
  • 1.789 arrondie à 1.75
  • 1.843 arrondie à 1.875
  • 1.898 arrondie à 1.875
  • 1.953 arrondie à 2.0
  • 2.007 arrondie à 2.0
  • 2.062 arrondie à 2.0
  • 2.117 arrondie à 2.0
  • 2.171 arrondie à 2.25
  • 2.226 arrondie à 2.25
  • 2.281 arrondie à 2.25
  • 2.335 arrondie à 2.25
  • 2.390 arrondie à 2.5
  • 2.445 arrondie à 2.5
Il convient de noter comment la limite supérieure de 2.5 serait retournée, malgré le fait que ce soit une limite ouverte et donc exclue. Il est également à noter comment 2.0 et 2.25 sont deux fois plus susceptibles d'être retournés par rapport aux autres valeurs.

Liste de paramètres

min

La limite inférieure de l'intervalle.

max

La limite supérieure de l'intervalle.

boundary

Spécifie si les limites de l'intervalle sont des valeurs de retour possibles.

Valeurs de retour

Une valeur flottante uniformément sélectionnée et équidistribuée de l'intervalle spécifié par min, max et boundary. Si boundary est Random\IntervalBoundary::ClosedClosed, min et max sont des valeurs de retour possibles.

Erreurs / Exceptions

Exemples

Exemple #1 Exemple de Random\Randomizer::getFloat()

<?php
$randomizer
= new \Random\Randomizer();

// Il est à noter que la granularité de la latitude est le double
// de la granularité de la longitude.
//
// Pour la latitude, la valeur peut être à la fois -90 et 90.
// Pour la longitude, la valeur peut être 180, mais pas -180, car
// -180 et 180 font référence à la même longitude.
printf(
"Lat: %+.6f Lng: %+.6f",
$randomizer->getFloat(-90, 90, \Random\IntervalBoundary::ClosedClosed),
$randomizer->getFloat(-180, 180, \Random\IntervalBoundary::OpenClosed),
);
?>

Résultat de l'exemple ci-dessus est similaire à :

Lat: +69.244304 Lng: -53.548951

Notes

Note:

Cette méthode implémente l'algorithme de la section γ tel que publié dans »  Dessiné des nombres flottants aléatoires d'un intervalle. Frédéric Goual pour obtenir les propriétés comportementales souhaitées.

Voir aussi

add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top