Arbeiten mit Fließkommazahlen

Nette\Utils\Floats ist eine statische Klasse mit nützlichen Funktionen zum Vergleichen von Fließkommazahlen (Floats).

Installation:

composer require nette/utils

Alle Beispiele setzen voraus, dass der folgende Alias definiert wurde:

use Nette\Utils\Floats;

Motivation

Sie fragen sich vielleicht, warum es überhaupt eine Klasse zum Vergleichen von Fließkommazahlen gibt? Man kann doch die Operatoren <, >, === verwenden und ist fertig. Das stimmt nicht ganz. Was denken Sie, gibt dieser Code aus?

$a = 0.1 + 0.2;
$b = 0.3;
echo $a === $b ? 'same' : 'not same';

Wenn Sie den Code ausführen, werden einige von Ihnen sicherlich überrascht sein, dass das Programm not same ausgibt.

Bei mathematischen Operationen mit Fließkommazahlen kommt es aufgrund der Konvertierung zwischen dem Dezimal- und Binärsystem zu Genauigkeitsfehlern. Beispielsweise ergibt 0.1 + 0.2 das Ergebnis 0.300000000000000044…. Deshalb müssen wir beim Vergleichen eine kleine Toleranz für Unterschiede ab einer bestimmten Dezimalstelle zulassen.

Und genau das erledigt die Klasse Floats. Der folgende Vergleich funktioniert nun wie erwartet:

echo Floats::areEqual($a, $b) ? 'same' : 'not same'; // same

Beim Versuch, NAN zu vergleichen, wird eine \LogicException ausgelöst.

Die Klasse Floats toleriert Unterschiede, die kleiner als 1e-10 sind. Wenn Sie mit höherer Präzision arbeiten müssen, verwenden Sie stattdessen die BCMath-Bibliothek.

Vergleich von Fließkommazahlen

areEqual (float $a, float $b)bool

Gibt true zurück, wenn $a = $b ist.

Floats::areEqual(10, 10.0); // true

isLessThan (float $a, float $b)bool

Gibt true zurück, wenn $a < $b ist.

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 ist.

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 ist.

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 ist.

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 ist, 0, wenn sie gleich sind, und 1, wenn $a > $b ist.

Kann beispielsweise mit der Funktion usort() verwendet werden.

$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.0