Überraschend float-int-Umwandlung in PHP
Nachdem er eine Stunde versucht, herauszufinden, warum ein PHP-Skript gab mir falsche Ausgabe, es stellte sich heraus, dass eine Schleife lief eine iteration kurzen in einem bestimmten Fall.
Um zu erklären, was Los ist: eine version-Nummer (2-stellig, z.B. 1.5 oder 2.0) Lesen aus einer XML-Attribut und mit 100 multipliziert. Das Skript später durchläuft einen definierten Bereich der versions-Nummer gruppiert.
Es stellt sich heraus, dass 410 == 409
gibt, die eine lustige überraschung, wenn Sie vergleichen einen Zähler, der inkrementiert in Schritten von 10 gegen diesen Wert.
Das bringt mich zu meiner Frage: Bin ich grundsätzlich Verständnis etwas falsch? Sicherlich 4.1
, 100
, und 410
sollten alle gut darstellbar, wie float-und sollte auch-Cabrio zu int ohne Rundungsfehler?
Jedoch auf meinem system (mit PHP-CLI 5.3.2, Zend Engine 2.3.0), der folgende Testfall
<?
$a = 100 * 4.1;
$b = (string) $a;
$c = (int) $a;
$d = (int)(string) $a;
var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
?>
Ausgänge:
float(410)
string(3) "410"
int(409)
int(410)
Ich bin jetzt dabei einen (int)(string)
Bekehrung, die funktioniert, aber dies ist eine Art von einem fiesen hack, der nicht hübsch ist und nicht ganz im Recht fühlen.
Gibt es eine bessere (richtige, kein hack) Lösung, um ein genaues Resultat?
- mögliche Duplikate von PHP Typisierung float->int
- 0,1 oder 1/10, ist nicht ausdrückbar ist genau in der Binärdatei. Eher wie 1/3 im Dezimalsystem.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Du normalerweise nicht sehen kann, ob ein Wert gut, umwandelbar in einen float-nur durch das betrachten es. Lesen Die Warnung in der Anleitung für ein Beispiel.
0.5 base 10 = 0.1 base 2
Ist das einfach.0.7 base 10 = 0.101100110011... base 2
So, inhärenten Wert, den Verlust, da die Umwandlung zurück zur Basis 10 ergibt0.6999999
oder so. "Es sieht nicht zu schlecht" zählt nicht für alles. 🙂Dein problem ist in der ersten Zeile:
Den float-literal
4.1
nicht, in der Tat, haben den Wert 4.1, und so das Ergebnis multipliziert mit 100 ist nicht 410 sondern ein bisschen weniger. Offenbar, Umwandlung in string-Runden, aber casting nach int rundet ab.Um die dezimal-Mathematik, das Sie erwarten, verwenden Sie die BC Math Funktionen.
Können Sie verwenden BC Math-Funktionen, um vorhersagbare Ergebnisse von float-Multiplikation
http://php.net/manual/en/ref.bc.php
Versuchen Sie es mit
intval
Edit:
Versuchen Rundung mit einer normalen Rundung:
$a = 100 * 4.1; var_dump(intval($a));
int(409)
Die Multiplikation mit 4.1 zurück schweben, wie Sie gesehen haben. Casting float zu int wird etwas tun, wie floor(), das bedeutet, dass, wenn das Ergebnis war 409.999... wird es wieder 409. Wenn Sie wollen, um die Arbeit mit ganzen zahlen, sollten Sie nicht entweder mischen float und integer-Werte in einer Berechnung zu verwenden, oder Sie verwenden sollten, round() hinterher, um die nächste Ganzzahl.
Möglichen Werte für eine exakte Darstellung wäre, 0.5, 0.25, 0.125, die Werte, die Sie bekommen können, mit Divisionen durch 2, da der Wert gespeichert ist, in das binäre system.