Question

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

$a = 34.56

$b = 34.55

$ a fait un calcul pour obtenir ce chiffre

$ b arrondit à 0,05 le plus proche pour obtenir ce chiffre

que se passe-t-il

$c = $b - $a

Je devrais être censé être -0,01, mais je répète que le $ c est affiché -0,00988888888888

J'essaie d'utiliser n umber_format ($ c, 2) , mais le résultat est 0,00,

comment puis-je m'assurer que $ a et $ b correspondent exactement à 2 décimales, pas de nombre caché à l'arrière.

dans ma connaissance php number_format ne pouvant formater que l'affichage, mais la valeur n'est pas vraiment 2 décimale,

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

Était-ce utile?

La solution

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

Les nombres en virgule flottante sont représentés dans la notation IEEE en fonction de la puissance de 2, de sorte que les nombres décimaux de fin ne sont peut-être pas des nombres binaires terminaux, c’est pourquoi vous obtenez les derniers chiffres.

Comme suggéré par Variable Length Coder, si vous connaissez la précision que vous souhaitez et qu'elle ne change pas (par exemple lorsque vous traitez avec de l'argent), il serait peut-être préférable d'utiliser simplement des nombres à virgule fixe, c'est-à-dire d'exprimer les nombres en cents plutôt que que des dollars

$a = 3456;

$b = 3455;

$c = $b - $a;

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

Ainsi, vous n’auriez aucune erreur d’arrondi si vous faites beaucoup de calculs avant d’imprimer.

Autres conseils

Utilisez round () :

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

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

Modifier: Ok, je ne comprends pas ce que sprintf () fait pour que number_format () ne soit pas:

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

vs

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

?

Calcul natif:

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

Fonctionne comme prévu (! utilisez toujours les fonctions BC pour le calcul des nombres réels, le problème concerne toutes les plates-formes C):

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

J'ai également rencontré ce problème récemment lors de calculs avec des flottants. Par exemple, j'avais 2 flottants qui, une fois soustraits et formatés, avaient une valeur de -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 était:

$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 dispose de capacités strfmon, Windows ne le fait pas.

Vous avez rencontré l'un des pièges des nombres en virgule flottante; qu'ils ne peuvent pas toujours représenter des fractions décimales exactes. Si vous voulez des valeurs décimales exactes, utilisez plutôt des entiers, puis divisez-les par la précision souhaitée.

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

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 de faire attention si vous transmettez des arguments sous forme de chaînes ou de types de données numériques.

Si quelqu'un accède 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.

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

Ce problème a même fait plusieurs victimes 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êchait d'intercepter un missile Scud entrant à Dhahran, en Arabie saoudite, contribuant à la mort de 28 soldats du 14e détachement de quartier-maître de l'armée américaine.

Mais pourquoi ça se passe?

La raison en est que les valeurs en virgule flottante représentent une précision limitée. Donc, une valeur pourrait ne pas avoir la même représentation de chaîne après tout traitement. Ça aussi comprend l'écriture d'une valeur en virgule flottante dans votre script et directement l’imprimer sans aucune opération mathématique.

Juste un exemple simple:

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

Vous vous attendez à ce qu'il imprime 0,01, non? Mais il va imprimer 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 forme de chaîne de 0 et de 1. La différence entre un nombre à virgule flottante et un nombre entier réside dans la façon dont nous interprétons les 0 et les 1 lorsque nous voulons les examiner. Il y a beaucoup de normes comment elles sont stockées.

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

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

Si 0.01 est conservé sous une forme simplifiée et tronquée par le système, 01000111101011100001010 en binaire, il est lu comme suit en décimal, il sera lu comme suit: 0.0099999 .... en fonction du système (les ordinateurs 64 bits vous donneront une bien meilleure précision que 32 bits). Le système d’exploitation décide dans ce cas si l’imprimer comme il le voit ou comment le rendre plus lisible par l’homme. La manière dont ils veulent le représenter dépend donc de la machine. Mais il peut être protégé au niveau de 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 il doit être lu et quelle précision vous exigez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top