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
Version: 4.x