web-dev-qa-db-fra.com

php float calcul 2 point décimal

Vous avez un problème de calcul mathématique.

$a = 34.56

$b = 34.55

$a Faites un calcul pour obtenir ce chiffre

$b Arrondit à 0,05 près pour obtenir ce chiffre

ce qui se produit est

$c = $b - $a

soi-disant ce sera -0.01, mais je fais écho au $c, qui montre -0.00988888888888

J'essaie d'utiliser number_format($c, 2), mais la sortie est 0,00,

comment puis-je m'assurer que $a et $b est exactement à 2 décimales, aucun chiffre caché à l'arrière.

dans ma connaissance de php, number_format est seulement capable de formater l'affichage, mais la valeur n'est pas vraiment 2 décimales,

J'espère que je pourrai obtenir de l'aide d'ici. Cela m'a vraiment frustré.

25
Shiro

Essayez sprintf("%.2f", $c);

Les nombres à virgule flottante sont représentés en notation IEEE sur la base des puissances de 2, donc les nombres décimaux de fin peuvent ne pas être un nombre binaire de fin, c'est pourquoi vous obtenez les chiffres de fin.

Comme suggéré par le codeur à longueur variable, si vous connaissez la précision que vous souhaitez et qu'elle ne change pas (par exemple lorsque vous avez affaire à de l'argent), il pourrait être préférable d'utiliser simplement des nombres à virgule fixe, c'est-à-dire d'exprimer les nombres en cents plutôt qu'en dollars.

$a = 3456;

$b = 3455;

$c = $b - $a;

sprintf ("%.2f", $c/100.0);

De cette façon, vous n'aurez aucune erreur d'arrondi si vous faites beaucoup de calculs avant d'imprimer.

53
Charles Ma

Utilisez round() :

$c = round($b - $a, 2);

Remarque: vous pouvez également choisir le mode d'arrondi approprié.

Edit: Ok Je ne comprends pas ce que sprintf() fait ça number_format() n'est pas:

$c = number_format($b - $a, 2);

contre

$c = sprintf("%.2f", $b - $a);

?

15
cletus

Vous pouvez très bien contourner tous ces problèmes simplement en utilisant la bibliothèque bcmath.

N'oubliez pas de lire la documentation et faites attention si vous passez des arguments sous forme de chaînes ou de types de données numériques.

5
Robert L

Calcul natif:

$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005    

Fonctionne comme prévu (! Utilisez toujours les fonctions BC pour les calculs de nombres réels, le problème concerne toutes les plateformes basées sur C):

$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100    
4

J'ai également rencontré ce problème récemment lors de calculs avec des flottants. Par exemple, j'avais 2 flottants qui, lorsqu'ils étaient soustraits et formatés, la valeur était -0,00.

$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00

Ce que j'ai fait, c'est:

$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00

Dans ma solution, je sais que floatOne ne sera jamais inférieur à floatTwo. La fonction money_format n'est définie que si le système a des capacités strfmon, ce n'est pas le cas de Windows.

4
jtaz

Vous avez rencontré l'un des pièges des nombres à virgule flottante; qu'ils ne peuvent pas toujours représenter des fractions décimales exactes. Si vous voulez des valeurs décimales exactes, il vaut mieux utiliser des entiers, puis diviser par la précision souhaitée à la fin.

Par exemple, si vous effectuez des calculs dans des flottants représentant des dollars (ou votre devise préférée), vous voudrez peut-être réellement faire vos calculs en cents entiers.

3

Si quelqu'un atteint encore cette page avec des problèmes similaires où la soustraction de nombres flottants provoque des erreurs ou des valeurs étranges. Je veux expliquer ce problème avec un peu plus de détails. Le coupable est le nombre à virgule flottante. Et différents systèmes d'exploitation et différentes versions de langages de programmation peuvent se comporter différemment.

Pour illustrer le problème, je vais expliquer pourquoi avec un exemple simple ci-dessous.

Il n'est pas directement lié à PHP et ce n'est pas un bug. Cependant, chaque programmeur doit être conscient de ce problème.

Ce problème a même coûté la vie à il y a deux décennies.

Le 25 février 1991, ce problème de calcul des nombres flottants dans une batterie de missiles MIM-104 Patriot l'empêcha d'intercepter un missile Scud entrant à Dhahran, en Arabie saoudite, contribuant à la mort de 28 soldats du 14e quartier-maître de l'armée américaine.

Mais pourquoi ça arrive?

La raison en est que les valeurs en virgule flottante représentent une précision limitée. Ainsi, une valeur peut ne pas avoir la même représentation sous forme de chaîne après tout traitement. Il comprend également l'écriture d'une valeur à virgule flottante dans votre script et son impression directe sans aucune opération mathématique.

Juste un exemple simple:

$a = '36';
$b = '-35.99';
echo ($a + $b);

Vous vous attendriez à ce qu'il imprime 0,01, non? Mais il affichera une réponse très étrange comme 0.009999999999998

Comme les autres nombres, les nombres à virgule flottante doubles ou flottants sont stockés en mémoire sous la forme d'une chaîne de 0 et de 1. La différence entre virgule flottante et entier réside dans la façon dont nous interprétons les 0 et les 1 lorsque nous voulons les regarder. Il existe de nombreuses normes sur leur stockage.

Les nombres à virgule flottante sont généralement regroupés dans une donnée informatique sous forme de bit de signe, de champ d'exposant et de signification ou de mantisse, de gauche à droite ....

Les nombres décimaux ne sont pas bien représentés en binaire en raison du manque d'espace suffisant. Donc, vous ne pouvez pas exprimer 1/3 exactement comme c'est 0.3333333 ..., non? Pourquoi nous ne pouvons pas représenter 0,01 comme un nombre flottant binaire est pour la même raison. 1/100 est 0.00000010100011110101110000 ..... avec un 10100011110101110000 répétitif.

Si 0,01 est conservé sous forme simplifiée et tronquée par le système de 01000111101011100001010 en binaire, lorsqu'il est converti en décimal, il sera lu comme 0,0099999 .... selon le système (les ordinateurs 64 bits vous donneront une bien meilleure précision que les 32 bits ). Le système d'exploitation décide dans ce cas s'il faut l'imprimer comme il le voit ou comment le rendre plus lisible par l'homme. Donc, cela dépend de la façon dont ils veulent le représenter. Mais il peut être protégé au niveau de la langue avec différentes méthodes.

Si vous formatez le résultat, echo number_format (0.009999999999998, 2); il imprimera 0,01.

C'est parce que dans ce cas, vous indiquez comment le lire et la précision dont vous avez besoin.

2
Selay