Dies ermöglicht wahrscheinlich die Prüfung von Epsilon mit einem relativen Fehler anstelle eines absoluten Fehlers.
Vergleichen Sie diese beiden Fälle:
function areEqual(float $a, float $b) : bool {
return abs(($a - $b)/$b) < 0.00001;
}
areEqual(10000, 10000.01);
areEqual(0.0000001, 0);
Tatsache über die Beispielwerte oben: Unsere epsilon hier ist 0.00001
für Bequemlichkeit ‐ die kleinste epsilon möglich ist, viel kleiner als diese Werte ohnehin, also lassen Sie uns diese Tatsache ignorieren . Unser Algorithmus geht davon aus, dass $a
und $b
beide ähnlich sind, also ist es egal, ob wir dividieren durch $a
oder $b
. Eigentlich sollte 10000
viel größer als das sein (ein sehr großer Exponent), und 0.0000001
kann viel kleiner sein, aber der Bequemlichkeit halber angenommen, dies sind die Werte, die Probleme verursachen können.
Jetzt können Sie bereits den Unterschied sehen.
Für die großen Zahlen: Wenn die verglichenen Floats extrem groß sind, kann Epsilon zu klein sein. Der Float intern kann nur eine bestimmte Anzahl von Ziffern für die Genauigkeit speichern, während der Exponent viel größer sein kann. Als Ergebnis würde die Quelle des Gleitkommafehlers, d. H. Die Endziffern der Gleitkommazahlen, an einer Stelle erscheinen, die höher als die Einheitsziffern sein kann.Mit anderen Worten, für extrem große Schwimmer kann der absolute Fehler größer als 1
sein, viel weniger unser epsilon 0.00001
.
Für die kleinen Zahlen: Dies ist noch offensichtlicher. Beide Zahlen sind bereits kleiner als das Epsilon. Selbst wenn Sie sie mit 0 vergleichen, während der relative Fehler unendlich groß ist, denken Sie immer noch, dass sie gleich sind. Für diesen Fall multiplizieren Sie entweder beide Operanden oder Sie verringern das Epsilon. Sie sind eigentlich die gleichen, aber in Bezug auf die Implementierung ist es bequemer, die Differenz mit einem der Operanden zu teilen, die für kleine Zahlen (/ 0.0001
ist gleich * 10000
) oder teilen für große Zahlen (/ 10000
während der Unterschied ist hoffentlich viel kleiner als 10000
)
Es gibt einen anderen Namen für diese Überprüfung. Während abs($a - $b)
der absolute Fehler genannt wird, verwenden wir normalerweise den relativen Fehler, der ein absoluter Fehler ist. Da die Werte auch negativ sein können, verwenden wir abs
das Ganze ($a - $b)/$b
stattdessen. Unser "Epsilon", 0.00001
, bedeutet in diesem Fall, dass unser relativer Toleranzfehler 0.00001
ist, d. H. 0,001% Fehler.
Denken Sie daran, dass dies
noch nicht absolut sicher ist. Nach zahlreichen Transformationen in Ihrem Programm können Sie zum Beispiel Ihre Zahlen mit einigen großen Zahlen addieren/multiplizieren, dann wieder subtrahieren und den unreinen Fehler in den großen Zahlen für den Menschen noch vernachlässigbar machen, aber bemerkenswert für Ihren Epsilon-Wert. Denken Sie deshalb immer zweimal darüber nach, bevor Sie einen Epsilon-Wert oder einen Float-Vergleichsalgorithmus wählen.
Vermeiden Sie es, große Zahlen mit kleinen Zahlen zu addieren, zu subtrahieren oder zu multiplizieren. Sie erhöhen die Wahrscheinlichkeit von Fehlern. Denken Sie bei der Entwicklung (vor allem Vereinfachung) Ihrer Algorithmen immer daran, dass es sich um einen Fehler in Ihren Floats handeln könnte. Dies kann die Arbeitsbelastung auf ein dummes Ausmaß erhöhen, aber solange Sie sich dessen bewusst sind, erspart Ihnen diese Art von Sorge manchmal, aus den Teams rausgeschmissen zu werden.
@luweiqi kein Duplikat, verschiedene Fragen. Ich habe sogar das vorgeschlagene Duplikat verlinkt. – Twifty
Yup, Ihre aktualisierte Frage ist klarer, ich habe meine enge Abstimmung zurückgezogen. Prost! – Panda
Related: http://stackoverflow.com/q/328475/3990767 – SOFe