2013-09-06 7 views
5

Ich habe ein assoziatives Array, dessen Werte Floats sind, die Wahrscheinlichkeiten sein sollen. Als solche habe ich sie auf und erfordern summieren, dass das Ergebnis in der Tat 1.Irgendwie 1 ist nicht gleich 1 (PHP)

$total = array_sum($array); 
echo '$total = '.$total."\n"; 
if ($total == 1) { 
    die("total is 1"); 
} else { 
    die("total is not 1"); 
} 

Diese mysteriöse Weise gibt:

$total = 1 
total is not 1 

Doing ein var_dump($total) Erträge float(1), und doch auch $total == (float)1 false zurück.

Was ist los?

+2

http://stackoverflow.com/questions/4682889/is-floating-point-ever-ok – thumbmunkeys

Antwort

2

Floats in PHP (und anderen Sprachen) ist nicht präzise, ​​deshalb könnte (float)1 tatsächlich sein 1.0000000000000 oder .99999999999999823477

PHP - Floating Number Precision für weitere Informationen beantworten Siehe

+0

gibt es eine Möglichkeit, PHP zu bekommen, um mir zu sagen, was sein tatsächlicher Wert ist? – Mala

+0

'print (number_format ($ myNumber, 32);' sollte Sie mit einiger Genauigkeit sehen lassen, was es ist, aber soweit ich weiß, können Sie den _exact_ Wert nicht sehen. – Jordan

+0

whargbl "0.99999999999999988897769753748435" - ich hatte keine Idee var_dump würde so runden – Mala

1

Guss

if ((int)$total == 1) 

int tun und es wird funktionieren :)

EDIT: oder noch besser

$total = (int)array_sum($array); 
+1

dies wäre leider nicht hilfreich mit dem, was ich versuche zu tun (siehe oben auf der Frage). Wenn meine Werte sind vermasselt - was dieser Code ist es zu überprüfen - und die Summe war in der Tat 1.3 es würde den Test bestanden – Mala

+0

Ich sehe, sorry, dass ich Ihre Frage falsch gelesen :( – Quillion

3

Gleitkomma-Werte sind von Natur aus ungenau und sind sehr selten gleich einen anderen aufgrund der Art, wie sie gespeichert werden und Rundungsfehler zu eins. Sie sollten Floats vergleichen, indem Sie sehen, ob die beiden Werte "nahe genug" sind. Das heißt, der Absolutwert der Differenz zwischen den beiden Werten wird mit einer signifikant kleinen Fehlerquote verglichen (oft als "Epsilon" bezeichnet).

Eine solche Implementierung kann:

if (abs($total - 1) < 0.000000001) 
    die("total is 1"); 
} else { 
    die("total is not 1"); 
} 

Beachten Sie, dass nur Anforderungen Ihrer Anwendung kann wirklich eine sichere Fehlerspanne bestimmen, was ist und an welchem ​​Punkt Zahlen sollten für die Anzeige gerundet werden.


Wenn Sie mit Währungswerten, zum Beispiel zu tun hat, und genaue Präzision erfordern, eine bessere Lösung wäre ganz Gleitkommaarithmetik zu verzichten. Eine Option wäre in diesem Fall, einen Integer-Typ zu verwenden und die Zahl als Cents zu speichern, die nur in der letzten Minute geteilt wird, um die Zahl für den Benutzer anzuzeigen (oder nicht einmal zu teilen und stattdessen einen Dezimalpunkt in die Zeichenfolge einzufügen).