Floats auf Gleichheit prüfen (Thema: PHP Beispiele)

Wie Floats im PHP am besten auf Gleichheit hin getestet werden

1. Einleitung

Floats zu Vergleichen ist keine triviale Aufgabe. Im Gegensatz zu Integern kann man für zwei Floats $a und $b nicht einfach ein schlichtes $a === $b verwenden, um herauszufinden, ob beide den selben Wert abbilden. Das liegt an der Ungenauigkeit von Floats, die dazu führen kann, dass zwei Floats, die eigentlich gleich sein sollten, trotzdem minimale Abweichung auf der x-ten Nachkommastelle haben. Diese würden dann bei einem Vergleich über $a === $b nicht als gleich angesehen werden, da sie nicht exakt gleich sind, sondern nur nahezu gleich. Das Beispiel stellt dieses Problem dar, 0,1 + 0,7 ist in PHP nicht das gleiche wie 0,8:

PHP-Code
<?php
	// 1.0 + 7.0 ist gleich 8.0
	$a = 1.0;
	$b = 7.0;
	var_dump($a+$b, $a+$b === 8.0); // 8 und true
	
	// 0.1 + 0.7 ist ungleich 0.8
	$a = 0.1;
	$b = 0.7;
	var_dump($a+$b, $a+$b === 0.8); // 0.8 und false
	
	// 0.1 + 0.3 ist gleich 0.4
	$a = 0.1;
	$b = 0.3;
	var_dump($a+$b, $a+$b === 0.4); // 0.4 und true
?>

HTML-Code: Ausgabe
float(8)
bool(true)
float(0.8)
bool(false)
float(0.4)
bool(true)


2. Vergleich anhand von Differenz (Epsilon)

Ein Weg zum Vergleich von Floats ist die Berechnung der Differenz und das anschließende Prüfen, ob diese Differenz unterhalb eines gewissen Schwellwerts (Epsilon) liegt. Dies wird im nächsten Beispiel von der Funktion isFloatEqual($a, $b, $epsilon) durchgeführt. $a und $b sind Float-Werte, $epsilon der Schwellwert. Es wird true zurückgegeben, falls der Betrag von $a minus $b kleiner als der Schwellwert ist. Mathematisch ausgedrückt muss also gelten: |$a-$b| < $epsilon.

PHP-Code
<?php
	function isFloatEqual($a, $b, $epsilon=0.0001) {
		return (abs($a - $b) < $epsilon);
	}
	
	var_dump(isFloatEqual(8.0, 1.0+7.0)); // true
	var_dump(isFloatEqual(0.8, 0.1+0.7)); // true
	var_dump(isFloatEqual(0.4, 0.1+0.3)); // true
	
	var_dump(isFloatEqual(1.0, 0.5+0.501)); // false
	var_dump(isFloatEqual(1.0, 0.5+0.50001)); // true
	var_dump(isFloatEqual(1.0, 0.5+0.50001, 0.000001)); // false
	var_dump(isFloatEqual(13.7, 27.3)); // false
?>

HTML-Code: Ausgabe
bool(true)
bool(true)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)


3. Vergleich durch Runden

Der zweite mögliche Weg erfolgt über das Runden beider Zahlen, um alle Abweichungen ab einer bestimmten Nachkommastelle zu ignorieren. Im nachfolgenden Beispiel rundet die Funktion isFloatEqual($a, $b, $decPlaces) die Float-Werte $a und $b auf $decPlaces Stellen nach dem Komma. Falls diese gerundeten Werte exakt gleich sind, wird true zurückgegeben. Sonst false. $decPlaces sollte nicht zu groß gewählt werden, um zu vermeiden, dass die gerundeten Zahlen ebenfalls unerwartete Ungenauigkeiten aufweisen. (Im Allgemeinen ist die vorherige Methode mit Epsilon vorzuziehen, da bei dieser weniger schief gehen kann.)

PHP-Code
<?php
	function isFloatEqual($a, $b, $decPlaces=3) {
		return (round($a, $decPlaces) === round($b, $decPlaces));
	}
	
	var_dump(isFloatEqual(8.0, 1.0+7.0)); // true
	var_dump(isFloatEqual(0.8, 0.1+0.7)); // true
	var_dump(isFloatEqual(0.4, 0.1+0.3)); // true
	
	var_dump(isFloatEqual(1.0, 0.5+0.501)); // false
	var_dump(isFloatEqual(1.0, 0.5+0.50001)); // true
	var_dump(isFloatEqual(1.0, 0.5+0.50001, 12)); // false
	var_dump(isFloatEqual(13.7, 27.3)); // false
?>

HTML-Code: Ausgabe
bool(true)
bool(true)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)


Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen zu Cookies erhalten Sie in unserer Datenschutzerklärung. OK