Maison  >  Article  >  développement back-end  >  Questions sur la précision des nombres à virgule flottante php

Questions sur la précision des nombres à virgule flottante php

怪我咯
怪我咯original
2017-07-11 13:56:103278parcourir

En langage C et en langage C#, les données de type à virgule flottante sont stockées en utilisant le type simple précision (float) et le type double précision (double). Les données Float occupent 32 bits. Les données doubles occupent 64 bits. Lorsque nous déclarons une variable float f= 2,25f, comment allouer la mémoire ? S'il est alloué de manière aléatoire, le monde ne serait-il pas dans le chaos ? En fait, float et double sont tous deux conformes aux spécifications IEEE en termes de méthodes de stockage, tandis que double est conforme à R64.53.

Qu'il s'agisse de simple précision ou de double précision, le stockage est divisé en trois parties :

Bit de signe (Sign) : 0 représente le positif, 1 représente le négatif

Bit d'exposant ( Exposant) : utilisé pour stocker des données exponentielles en notation scientifique et utilise le stockage par décalage

Partie mantisse (Mantissa) : partie mantisse

Cet article présente principalement les nombres à virgule flottante PHP Résumé des problèmes de précision. L'article se concentre sur le problème de la perte de précision en virgule flottante PHP. Il utilise trois paragraphes pour expliquer les causes et les solutions à ce problème de différentes manières. Les amis dans le besoin peuvent se référer à

1. PHP Le problème de. perte de précision en virgule flottante

Regardez d'abord le code suivant :

Le code est le suivant :

$f = 0.57;
echo intval($f * 100);  //56

Le résultat peut être un peu surprenant, PHP suit la double précision IEEE 754 :

Le nombre à virgule flottante, avec une double précision de 64 bits, est représenté par 1 bit de signe (E), 11 bits d'exposant (Q) et 52 mantisses (M ) (un total de 64 bits).
Bit de signe : le bit le plus élevé représente le signe des données, 0 représente un nombre positif et 1 représente un nombre négatif.
Bit exposant : représente la puissance des données en base 2, et l'exposant est représenté par un code de décalage
Mantisse : représente les chiffres significatifs après la virgule décimale des données.

Prenons un aperçu de la façon dont les décimales sont représentées en binaire :

Multipliez par 2 et arrondissez, rangez dans l'ordre, c'est-à-dire multipliez la partie décimale par 2, puis prenez la partie entier, continuez pour multiplier la partie décimale restante par 2, puis prendre la partie entière, et la partie décimale restante. La partie est à nouveau multipliée par 2 jusqu'à ce que la partie décimale soit prise. Cependant, si une décimale comme 0,57 est multipliée comme ceci, la partie décimale ne peut pas. être 0. La représentation décimale des chiffres significatifs est infinie en binaire.

La représentation binaire de 0,57 est essentiellement (52 bits) : 0010001111010111000010100011110101110000101000111101

S'il n'y a que 52 bits, 0,57 =》 0,56999999999 9 99995

Ce n'est pas difficile de voir l'inattendu résultats ci-dessus, non?

2. Problème de précision des nombres à virgule flottante PHP

Regardons d'abord le problème :

Le code est le suivant :

$f = 0.58;
var_dump(intval($f * 100)); //为啥输出57

Je crois que de nombreux étudiants se sont posés de telles questions.

Pour le principe spécifique, vous pouvez lire un article de "Brother Bird", où il y a une explication détaillée : Réponses à une FAQde nombres à virgule flottante PHP

Alors comment éviter cela. Quel genre de problème ?
Il existe de nombreuses façons, en voici deux :
1 sprintf

Le code est le suivant :

substr(sprintf("%.10f", ($a/ $b)), 0, -7);

2. rond (note Sera arrondi)

Le code est le suivant :

round($a/$b, 3);

Ou si vous avez une meilleure façon, veuillez laisser un message et dites-le-moi.

3. Réponses à une question courante sur les nombres à virgule flottante PHP

Concernant les nombres à virgule flottante PHP, j'ai déjà écrit un article : Ce que vous devez savoir sur les nombres flottants PHP. numéros de points (Tous les "faux" à propos du float en PHP)

Cependant, j'ai raté une chose à l'époque, qui est la réponse à la question courante suivante :

Le code est la suivante :

<?php
    $f = 0.58;
    var_dump(intval($f * 100)); //为啥输出57
?>

Pourquoi la sortie est-elle 57 ? Est-ce un bug en PHP ?

Je crois que de nombreux étudiants ont eu de telles questions, car beaucoup de gens me posent des questions similaires des questions, et bien plus encore. Inutile de dire que les gens se posent souvent sur bugs.php.net...

Pour comprendre cette raison, il faut d'abord connaître la représentation des nombres à virgule flottante (IEEE 754) :

Nombres à virgule flottante, sous forme 64 bits. Par exemple, la longueur (double précision) sera représentée par 1 bit de signe (E), 11 bits d'exposant (Q) et 52 bits de mantisse (M) (un total de 64 bits).

Bit de signe : représenté par le bit le plus élevé Le signe de la donnée, 0 représente un nombre positif et 1 représente un nombre négatif.

Bit exposant : représente la puissance des données en base 2, et l'exposant est représenté par un code décalé

Mantisse : représente les chiffres significatifs après la virgule décimale des données.

Les points clés ici Cela réside dans la représentation des décimales en binaire. Concernant la façon de représenter les décimales en binaire, vous pouvez effectuer une recherche sur Baidu. Je n'entrerai pas dans les détails ici. La chose clé que nous devons comprendre est celle-ci. représentation binaire, 0,58 est une valeur infinie (les nombres ci-dessous en omettant le 1 implicite). en gros (52 bits) : 0010001 111010111000010100011110101110000101000111101

Et deux Ou binaires, s'ils sont calculés uniquement à travers ces 52 bits, ils sont :




Copiez le code

Le code est le suivant :

Quant à 0,58 * Nous n'examinerons pas en détail la multiplication spécifique à virgule flottante de 100. Ceux qui sont intéressés peuvent la regarder (Nous l'examinerons vaguement avec mental). arithmétique... 0,58 * 100 = 57,999999999
0.58 -> 0.57999999999999996
0.57 -> 0.56999999999999995

Ensuite vous pouvez l'intvaliser, naturellement Cela fait 57…

On peut voir que le point clé de ce problème est : "Votre décimal apparemment fini est en réalité infini dans la représentation binaire de l'ordinateur"

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn