Maison  >  Article  >  développement back-end  >  Ce que vous devez savoir sur les nombres à virgule flottante PHP

Ce que vous devez savoir sur les nombres à virgule flottante PHP

藏色散人
藏色散人avant
2019-11-29 11:12:192335parcourir

Vous devez savoir tous les « faux » sur le float en PHP (Tous les « faux » sur le float en PHP)

PHP est un langage faiblement typé. De telles fonctionnalités doivent être requises de manière transparente. conversion de type implicite transparente, PHP utilise zval en interne pour enregistrer tout type de valeur. La structure de zval est la suivante (5.2 à titre d'exemple) :

struct _zval_struct {
    /* Variable information */
    zvalue_value value;     /* value */
    zend_uint refcount;
    zend_uchar type;    /* active type */
    zend_uchar is_ref;
};

Dans la structure ci-dessus, la valeur réelle elle-même est enregistrée par le. zvalue_value union. :

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value */
    zend_object_value obj;
} zvalue_value;

Le sujet d'aujourd'hui, nous nous concentrons uniquement sur deux membres, lval et dval. Nous devons réaliser que long lval a une longueur indéfinie en fonction de la longueur des mots du compilateur et du système d'exploitation. être 32 bits ou 64 bits, et le double dval (double précision) est stipulé par IEEE 754. Il est de longueur fixe et doit être de 64 bits

N'oubliez pas ceci, ce qui rend certains codes PHP "non indépendants de la plate-forme" "propriété. ". Notre discussion suivante, sauf indication contraire, suppose que long est une méthode de comptage à virgule flottante 64 bits

IEEE 754. Je ne la citerai pas ici. Si vous êtes intéressé, vous pouvez le vérifier par vous-même. La clé Un point est que la mantisse du double est stockée sur 52 bits en comptant le 1 bit significatif caché, le total est de 53 bits.

Ici, une question intéressante se pose. Utilisons le code c comme exemple ( en supposant que long est de 64 bits) :

  long a = x;
    assert(a == (long)(double)a);

Excusez-moi, lorsque la valeur de a se situe dans quelle plage, le code ci-dessus peut être considéré comme réussi (Laissez la réponse à la fin de l'article)

Revenons maintenant au sujet PHP Avant d'exécuter un script, vous devez d'abord lire le script et l'analyser. Ce processus inclut également la zvalisation des littéraux dans le script. Par exemple, pour le script suivant :

.
<?php
$a = 9223372036854775807; //64位有符号数最大值
$b = 9223372036854775808; //最大值+1
var_dump($a);
var_dump($b);

Sortie :

int(9223372036854775807)
float(9.22337203685E+18)

En d'autres termes, lors de l'étape d'analyse lexicale, PHP jugera si une valeur littérale dépasse la longue plage de valeurs de la table du système actuel. Sinon, lval sera utilisé pour sauvegarder. et zval sera IS_LONG, sinon utilisez simplement dval pour le représenter, zval IS_FLOAT.

Nous devons être prudents avec toute valeur supérieure à la plus grande valeur entière, car elle peut entraîner une perte de précision :

<?php
$a = 9223372036854775807;
$b = 9223372036854775808;
 
var_dump($a === ($b - 1));

Le résultat est faux.

Poursuivons maintenant la discussion au début, comme mentionné précédemment, les entiers de PHP peuvent être de 32 bits ou 64 bits, il est donc décidé que certains codes qui peuvent s'exécuter normalement sur 64 bits peut échouer en raison d'une conversion de type invisible entraînant une perte de précision, empêchant le code de fonctionner correctement sur les systèmes 32 bits

Par conséquent, nous devons nous méfier de cette valeur critique. a été défini en PHP :

<?php
    echo PHP_INT_MAX;
 ?>

Bien sûr, pour être sûr, nous devons utiliser des chaînes pour enregistrer de grands entiers et utiliser des bibliothèques de fonctions mathématiques telles que bcmath pour effectuer des calculs.

De plus, il existe une configuration clé qui nous rendra confus. Cette configuration est php.precision. Cette configuration détermine le nombre de bits significatifs que PHP génère lorsqu'il génère une valeur flottante.

Enfin, revenons sur la question soulevée. ci-dessus, qui est un long Quelle est la valeur maximale d'un entier pour garantir que la précision ne sera pas perdue lorsqu'il est converti en float puis reconverti en long ?

Par exemple, pour un entier, nous savons que sa représentation binaire est 101. Maintenant, décalons deux bits vers la droite pour devenir 1,01, supprimons le bit significatif implicite 1 du bit haut, et nous obtenons la valeur binaire de 5 stockée dans le double :

0/*符号位*/ 10000000001/*指数位*/ 0100000000000000000000000000000000000000000000000000

La représentation binaire de 5, qui est enregistrée dans la partie La mantisse, dans ce cas, est convertie de double back en long sans perte de précision.

Nous savons que double utilise 52 bits pour représenter la mantisse . En comptant le premier 1 implicite, il y a un total de 53 bits de précision. On peut alors conclure que si la valeur d'un entier long est inférieure à :

2^53 - 1 == 9007199254740991; //牢记, 我们现在假设是64bits的long

, alors cet entier ne perdra pas en précision lorsque. la conversion de valeur long->double->long se produit

Recommandé : "Tutoriel PHP"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer