float/double Gleichstellung mit genau null
Habe ich einen Algorithmus, der verwendet floats
oder doubles
um einige Berechnungen auszuführen.
Beispiel:
double a;
double b;
double c;
...
double result = c / (b - a);
if ((result > 0) && (result < small_number))
{
//result is relevant...
} else {
//result not required...
}
Nun, ich bin besorgt über (b - a)
auch null sein kann. Wenn es ist nahe null, aber nicht gleich null ist, es spielt keine Rolle, weil die result
werden außerhalb der Reichweite ist, um nützlich zu sein, und ich auch schon feststellen, dass (wie (b - a)
null nähert, result
Ansatz +/- inf, die nicht in den Bereich 0
-small_number
...)
Aber wenn das Ergebnis (b - a)
genau null, ich erwarte, dass etwas Plattform abhängig wird passieren, wegen Division durch null. Ändern könnte ich die if
Anweisung:
if ((!((b-a) == 0.0)) && ((result = c/(b-a)) > 0) && (result < small_number)) {
aber ich weiß nicht, ob (b-a) == 0.0
wird immer erkennen, dass Gleichheit mit null. Ich habe gesehen, es gibt mehrere Darstellungen für exakte null-floating-point? Wie können Sie testen für Sie alle, ohne dabei einige epsilon überprüfen, die ich nicht brauchen (ein kleines epsilon ignoriert werden in meinem Algorithmus)?
Was ist die Plattform-unabhängige Art und Weise zu überprüfen?
EDIT:
Nicht sicher, ob es war deutlich genug zu den Menschen. Im Grunde möchte ich wissen, wie zu finden, wenn ein Ausdruck wie:
double result = numerator / denominator;
Ergebnis wird in eine Fließkomma-Ausnahme, eine cpu-exception, ein signal vom Betriebssystem oder etwas anderes.... ohne tatsächlich die Durchführung der Betriebs-und sehen, ob es "werfen"..., weil das erkennen einer "throw" dieser Art scheint zu sein, kompliziert und Plattform-spezifische.
Ist ( (denominator==0.0) || (denominator==-0.0) ) ? "Will 'throw'" : "Won't 'throw'";
genug?
- Auch wenn
b - a
ist nicht genau null ist, wird der Betriebc / (b - a)
könnte noch überlaufen und senden Sie den Wert auf+/-INF
. - Das ist in Ordnung, man sollte das Ergebnis außerhalb des Bereichs von Interesse für mein problem.
- Es ist schwer zu finden, eine Umsetzung, die nicht IEEE-floating-point. Also ich denke, es ist sicher anzunehmen, dass die division durch
0
einfach Ertrag+INF
oder-INF
? Jemand korrigiert mich wenn ich falsch bin? - Hängt davon ab, was der Zähler ist. Offenbar
0.0 / 0.0
ist "NaN", und löst eine andere FP Ausnahme bei Ausnahmen aktiviert sind. - Ah, guter Punkt. Ich glaube nicht, dass - vor allem die
0.0 / 0.0
Fall. - BTW, Mystische teilweise richtig ist. gcc wird einfach ein segmentation fault, das ist (glaube ich) eine un-abfangbare Ausnahme. Auf jeden Fall eine Division durch null darf nie eine Ausnahme gefangen. Ich denke, das ist eine gute Frage und meiner Meinung nach, jede person schriftlich eine division operator sollten Sie immer prüfen, für null unabhängig von der code
- Versuchen Neuordnung der Zustand so, dass Sie die Division durch
small_number
stattb-a
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es hängt davon ab, wie
b
unda
haben Ihre Werte. Zero ist eine exakte Darstellung in floating-point-format, aber das größere problem würde sein, die fast-aber-nicht-ganz-null-Werte. Es würde immer sicher sein, zu überprüfen:Wo 0.00000001 ist was Wert Sinn macht.
b - a
mit einem Wert von1e-300
. So ein test kostet wenig und ist ideal Versicherung für den Widerstand gegen morphing code, auch wenn eine version davon produzieren kann, dass Wert.0
zusmall_number
das ist der Bereich, in dem ich interessiert bin.abs()
die funktioniert mit alle skalaren Typen.double result = c / ((abs((b - a)) > 0.00000001f) ? (b - a) : 0.00000001f) ;
diesem Ausdruck ist, aber hässlich wie die Sünde.Hier ist, wie Sie es tun: statt Kontrolle für
(result < small_number)
überprüfen Sie fürDann werden alle Ihre sorgen verschwinden! Die Berechnung der
c/(b-a)
wird nie überlaufen, wenn dieser test bestanden ist.Ich denke, dass Sie Sie verwenden können,
fpclassify(-0.0) == FP_ZERO
. Dies ist aber nur sinnvoll, wenn Sie prüfen wollen, wenn jemand hat eine Art von null-in-float-type-variable. Wie viele schon sagten, wenn Sie wollen, um zu überprüfen, Ergebnis der Berechnung erhalten Sie möglicherweise die Werte sehr nahe bei null aufgrund der Art der Darstellung.In Kürze, können wir wissen, eine floating-Zahl ist NULL genau dann, wenn wir es kennen, darstellen-format.
In der Praxis, vergleichen wir
x
mit einer kleinen Anzahl. Und wennx
weniger als diese Zahl, wir denkenx
ist die gleiche wie NULL-funktional (aber die meisten der Zeit unsere kleinen Zahl ist immer noch größer als null). Diese Methode ist sehr einfach, effizient und können auf cross-Plattform.Eigentlich, die
float
unddouble
wurden präsentiert von special-format, und die weit verbreitet ist IEEE 754 in aktuelle hardware, die geteilt die Zahl in Vorzeichen, exponent und Mantisse (Mantisse) bits.So, wenn wir wollen, um zu überprüfen, ob eine float-Zahl ist NULL genau, können wir überprüfen, ob die beiden Exponenten und die Mantisse NULL ist, siehe hier.
Nehmen
float
können wir zum Beispiel schreiben Sie einen einfachen code zu extrahieren, exponent und Mantisse bit und dann überprüfen Sie es.Test-Ergebnisse:
Weitere Beispiele:
Lassen Sie uns überprüfen, wenn die
float
wird echt NULL mit code.Ich glaube, dass
(b-a)==0
wahr sein wird, genau in den Fällen, wenn diec/(b-a)
würde scheitern, weil der(b-a)
null ist. Die float-Mathematik ist schwierig, aber hinterfragen, das ist übertrieben meiner Meinung nach. Auch ich glaube, dass die(b-a)==0
wird entsprichtb!=a
.Unterscheidung von positiven und negativen 0 ist auch nicht notwendig. Siehe z.B. hier Nicht-Schwimmer haben eine negative null? (-0f)
e1 && e2
, die Reihenfolge der Auswertung ist definiert.e2
wird immer ausgewertet, nache1
und nur, wenne1
zu true ausgewertet/ungleich null.Für epsilon, in der es eine standard-template-definition std::numeric_limits::epsilon(). Ich denke, die überprüfung der Unterschied größer als der std::numeric_limits::epsilon() sollte sicher genug, um Schutz gegen division durch null. Keine Plattform-Abhängigkeit hier, denke ich.
std::numeric_limits::epsilon()
ist nicht beabsichtigt, für diese Nutzung, es misst den ULP nur über1.0
. Und bei der Division durchx
division durch null tritt nur auf, wennx == 0
(überlauf kann auftreten, aber das wurde bereits hingewiesen).UPDATE (2016-01-04)
Ich habe einige downvotes auf diese Antwort, und ich fragte mich, ob ich sollte Sie einfach löschen. So scheint es der Konsens (https://meta.stackexchange.com/questions/146403/should-i-delete-my-answers) ist, dass das löschen von Antworten ist nur in extremen Fällen.
So, meine Antwort ist falsch. Aber ich denke, ich lasse es, weil es sorgt für eine interessante "think out of the box" eine Art Gedankenexperiment.
===============
Bingo,
Sagen Sie, Sie wollen wissen, wenn b-a == 0.
Andere Art der Betrachtung dieser ist zu ermitteln, ob a == b ist. Wenn a gleich b, dann ist b-a ist gleich 0.
Andere interessante Idee die ich gefunden habe:
http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm
Im wesentlichen, Sie nehmen die floating-point-Variablen, die Sie haben und sagen Sie dem compiler zu interpretieren Sie neu (bit für bit) Ganzzahlen mit Vorzeichen, wie im folgenden:
Dann vergleichen Sie die zahlen, und nicht schwimmende Punkte. Vielleicht hilft? Vielleicht auch nicht. Viel Glück!
if (a!=b) { /* do the math */ }
ist gut genug für diesen Fall; alles andere ist overkill.*(int*)&b == *(int*)&a
breaks strict-aliasing-Regeln, aber es macht+0.
anders erscheinen-0.
. Ich sehe keinen Punkt, um mit diesem Vergleich hier.int
ist 32 bit unddouble
64, man ist also nur der Vergleich der hoch oder niedrig (je nach Plattform) 32 bits für die Gleichstellung, die ist nutzlos. (Plus, würde es den Vergleich von zwei NaN als gleich, wenn Sie geschehen, um die gleichen bits gesetzt, und ungleich, wenn Sie nicht, das ist definitiv nicht sinnvoll...)Könnten Sie versuchen,
(b-a)
und(a-b)
würde produzieren die gleiche version von zero in floating point?