Arbeiten mit Fließkommazahlen
Nette\Utils\Floats ist eine statische Klasse mit nützlichen Funktionen zum Vergleichen von Fließkommazahlen.
Installation:
composer require nette/utils
Alle Beispiele setzen voraus, dass dieser Klassen-Alias definiert ist:
use Nette\Utils\Floats;
Motivation
Sie fragen sich, wozu wir eine Klasse zum Vergleichen von Fließkommazahlen brauchen? Sie können doch die Operatoren
<, >, === verwenden und fertig, oder? Nun, ganz so ist es nicht. Was gibt dieser Code
Ihrer Meinung nach aus?
$a = 0.1 + 0.2;
$b = 0.3;
echo $a === $b ? 'gleich' : 'nicht gleich';
Wenn Sie den Code ausführen, wird manche von Ihnen überraschen, dass das Programm nicht gleich ausgibt.
Mathematische Operationen mit Fließkommazahlen können wegen der Umwandlung zwischen dezimaler und binärer Darstellung zu
Genauigkeitsfehlern führen. Zum Beispiel ergibt 0.1 + 0.2 etwas wie 0.300000000000000044…. Beim
Vergleichen von Fließkommazahlen müssen wir deshalb eine kleine Abweichung tolerieren, ein Epsilon.
Und genau das erledigt die Klasse Floats. Der folgende Vergleich funktioniert nun wie erwartet:
echo Floats::areEqual($a, $b) ? 'gleich' : 'nicht gleich'; // gleich
Der Versuch, NAN zu vergleichen, wirft eine \LogicException.
Die Klasse Floats vergleicht mit einer relativen Genauigkeit von etwa 1e-10. Wenn Sie mit
höherer Genauigkeit arbeiten müssen, ziehen Sie stattdessen die Bibliothek BCMath in Betracht.
Vergleich von Fließkommazahlen
areEqual (float $a, float $b): bool
Gibt true zurück, wenn $a = $b.
Floats::areEqual(10, 10.0); // true
isLessThan (float $a, float $b): bool
Gibt true zurück, wenn $a < $b.
Floats::isLessThan(9.5, 10.2); // true
Floats::isLessThan(INF, 10.2); // false
isLessThanOrEqualTo (float $a, float $b): bool
Gibt true zurück, wenn $a <= $b.
Floats::isLessThanOrEqualTo(9.5, 10.2); // true
Floats::isLessThanOrEqualTo(10.25, 10.25); // true
isGreaterThan (float $a, float $b): bool
Gibt true zurück, wenn $a > $b.
Floats::isGreaterThan(9.5, -10.2); // true
Floats::isGreaterThan(9.5, 10.2); // false
isGreaterThanOrEqualTo (float $a, float $b): bool
Gibt true zurück, wenn $a >= $b.
Floats::isGreaterThanOrEqualTo(9.5, 10.2); // false
Floats::isGreaterThanOrEqualTo(10.2, 10.2); // true
compare (float $a, float $b): int
Gibt -1 zurück, wenn $a < $b, 0, wenn sie gleich sind, und
1, wenn $a > $b.
Verwenden lässt sie sich zum Beispiel mit der Funktion usort().
$arr = [1, 5, 2, -3.5];
usort($arr, [Floats::class, 'compare']);
// $arr ist jetzt [-3.5, 1, 2, 5]
Hilfsfunktionen
isZero (float $value): bool
Gibt true zurück, wenn der Wert null ist.
Floats::isZero(0.0); // true
Floats::isZero(0); // true
isInteger (float $value): bool
Gibt true zurück, wenn der Wert eine ganze Zahl ist.
Floats::isInteger(0); // true
Floats::isInteger(0.0); // true
Floats::isInteger(-5.0); // true
Floats::isInteger(-5.1); // false
Floats::isInteger(INF); // false
Floats::isInteger(NAN); // false