PHP String -> float -> int: Verlust von 1

Wahrscheinlich ist das Ergebnis von $php * 100 nicht 124936 sondern 124935,99999999999999999999999999.
Nur das der aufgerundete Wert angezeigt wird.
Floats sind halt nicht sehr genau.
 
Code:
$float1 = 1249.36999999999;
$float2 = 1249.3699999999;
var_dump($float1);
var_dump($float2);
Code:
float(1249.37) 
float(1249.3699999999)

Ok, das sehe ich auch irgendwie ein, aber ich würde dann doch erwarten, dass mir var_dump zumindest die korrekte Zahl ausgibt, die auch intern verwendet wird. Gibt es für solche Zwecke bessere Funktionen als var_dump?

Oder anders ausgedrückt: Wie vergleiche ich, ob eine Zahl aus einer MySQL decimal Zahl einem erwarteten berechneten Wert entspricht? Meine derzeitige Lösung sieht so aus:
Code:
(string)floatval($sum) !== (string)floatval($sumCheck)
das kann doch nicht die saubere Lösung sein ;-)
 
Hallo,
ist wohl ein Rundungsproblem. Das kommt bei Java raus:

Rundungsfehler.png

greetz
​hroessler
 
Deine Ausgabe von Java ist das was ich von var_dump aus PHP erwarten würde...
Dass float Operationen kritisch sind, ist ärgerlich, aber leider nicht zu verhindern. Aber ich würde dann doch zumindest beim debuggen erwarten, dass PHP mir das darstellen kann. Selbst debug_zval_dump versagt kläglich. Gibt es da irgendwelche debug Möglichkeiten?

Code:
$php = '1249.3600';
debug_zval_dump($php);
debug_zval_dump($php * 100);
debug_zval_dump(intval($php * 100));
 
Ich bin jetzt nicht der große PHP-Experte, aber das könnte an der dynamischen Typisierung von PHP liegen. Evtl. macht PHP hier irgendwelche casts die zu diesem Ergebnis führen.

greetz
hroessler
 
PW-toXic schrieb:
Oder anders ausgedrückt: Wie vergleiche ich, ob eine Zahl aus einer MySQL decimal Zahl einem erwarteten berechneten Wert entspricht? Meine derzeitige Lösung sieht so aus:
Code:
(string)floatval($sum) !== (string)floatval($sumCheck)
das kann doch nicht die saubere Lösung sein ;-)

Regel Nummer 1 von Floats: Man vergleicht nicht mit Eindeutigkeit. Du prüfst ob zwei Flaots "identisch" sind, indem du schaust ob nur ein sehr kleiner Delta-Wert (Theta) Unterschied zwischen beiden ist:
Code:
abs($float - $float2) <= 0.0000000001

Begründung: Floats sind nicht assoziativ, d.h. a + b + c kann ein anderes Ergebnis haben als b + a + c. Du kannst dir nie sicher sein, dass wirklich haargenau ein erwarteter Wert rauskommt. Wenn das wirklich nötig ist rechne nur mit Integern oder arbeite mit Erweiterungen die genaues Rechnen mit Nachkommastellen ermöglichen wie bcmath.
 
Zuletzt bearbeitet:
versuche
Code:
(integer)strval($php * 100)

oder
Code:
intval(strval($php * 100))
 
Super Antwort von ice-breaker!
Ich habs jetzt allerdings mit round() gelöst. Erfüllt den gleichen Zweck.

Falls aber doch jemand eine hilfreiche debug Funktion kennt, dann wäre ich dem sehr verbunden. Man hat in der Praxis nun mal häufig mit Code zu tun, wo mit floats jongliert wird. Wenn dann mal was schief läuft ist man dann am rätseln ...
 
Wie wärs statt mit Debug Funktionen mit einem richtigen Debugger/IDE zu arbeiten? xDebug z.B. Ist bei mir einige Zeit her, aber der sollte doch sehr genaue Informationen über Variablenzustände ausgeben...
 
ice-breaker schrieb:
Begründung: Floats sind nicht assoziativ, d.h. a + b + c kann ein anderes Ergebnis haben als b + a + c.

Du hast zwar völlig recht mit der potentiell unterschiedlichen Präzision des Ergebnisses, aber mit der Assoziativität des Plus-Operators hinsichtlich Floats an sich hat das nichts zu tun, natürlich sind die beiden Ausdrücke gleichwertig.
 
Zuletzt bearbeitet:
weil man in PHP strings mit floats und integers und bools addieren kann. Je nach dem was links steht kommt ein anderes Ergebnis
Ergänzung ()

Ok in diesem Fall habe ich PHP unrecht getan. Es verhält sich nicht so seltsam wie Javascript:
Code:
$string = '12a';
$integer = 24;
$float = 33.3;
$bool = true;

var_dump($string + $integer);
var_dump($integer + $string);
var_dump($integer + $float);
var_dump($float + $integer);
var_dump($string + $float);
var_dump($float + $string);
var_dump($string + $bool);
var_dump($bool + $string);
Code:
int(36)
int(36)
float(57.3)
float(57.3)
float(45.3)
float(45.3)
int(13)
int(13)

Ich habe allerdings Erinnerungen, dass man Fälle bei PHP gibt, wo man sich eben nicht darauf verlassen kann. Kann aber gerade keinen Fall konstruieren der das aufzeigt.
 
Zuletzt bearbeitet:
ice-breaker bezog sich oben doch klar auf die Addition von Floats, nicht auf beliebige Datentypen.
Und auch wenn ich mich mit PHP nicht auskenne, so denke ich kaum, dass "5" + 0.3 + 10 + true im Rahmen der Fließkomma-Präzision in einem anderen Ergebnis resultiert als true + 10 + "5" + 0.3. Kannst du da mal ein Beispiel anführen?
 
Du könntest dir testweise mal die Binärrepräsentation der Zahl anschauen. Laut PHP-Doku könnte das vielleicht mit pack gehen. Wenn du weißt, wie eine IEEE 754 Zahl aufgebaut ist, dann kannst du die binäre Darstellung hernehmen und mit einem geeignet genauen Taschenrechner (evt. tut es da die Wolfram-Alpha Website) nachschauen, welche Zahl wirklich dahinter steckt. Voraussetzung ist, das dieser pack-Befehl auch tatsächlich die IEEE Repräsentation des Floats ausspuckt.

Die Java-Löung oben ist keine Referenz, denn der Kollege dort verwendet auch Double, nicht Float. Hier mal als Vergleich:

floatdouble.PNG

edit:

Direkt aus der PHP-Doku, kommt dir das Problem bekannt vor? :)

warn.PNG
 
Zuletzt bearbeitet: (Beitrag wiederhergestellt)
Zurück
Oben