Frage

Um das Problem kurz machen sagen wir, ich den Ausdruck a / (b - c) auf floats berechnen möchten.

Um sicherzustellen, dass das Ergebnis sinnvoll ist, kann ich überprüfen, ob b und c in gleich ist:

float EPS = std::numeric_limits<float>::epsilon();
if ((b - c) > EPS || (c - b) > EPS)
{
    return a / (b - c);
}

aber meine Tests zeigen, es ist nicht genug zu garantieren entweder aussagekräftige Ergebnisse noch nicht versagt, ein Ergebnis zu liefern, wenn es möglich ist.

Fall 1:

a = 1.0f;
b = 0.00000003f;
c = 0.00000002f;

. Ergebnis: Die, wenn die Bedingung nicht erfüllt ist, aber der Ausdruck würde ein korrektes Ergebnis 100000008 (wie für die Präzision Floats) erzeugt

Fall 2:

a = 1e33f;
b = 0.000003;
c = 0.000002;

. Ergebnis: Die, wenn die Bedingung erfüllt ist, aber der Ausdruck erzeugt kein sinnvolles Ergebnis +1.#INF00

Ich fand es sehr viel zuverlässiger das Ergebnis zu überprüfen, nicht die Argumente:

const float INF = numeric_limits<float>::infinity();
float x = a / (b - c);
if (-INF < x && x < INF)
{
     return x;
}

Aber was ist das epsilon dann und warum jeder sagt epsilon ist gut zu bedienen?

War es hilfreich?

Lösung

„Sie müssen eine epsilon verwenden, wenn mit Schwimmern zu tun“ ist eine reflexartige Reaktion von Programmierern mit einem oberflächlichen Verständnis von Floating-Point-Berechnungen, für Vergleiche im allgemeinen (nicht nur auf Null).

Dies ist in der Regel nicht hilfreich, weil es Ihnen nicht sagen, wie die Ausbreitung von Rundungsfehlern zu minimieren, ist es Ihnen nicht sagen, wie Aufhebung oder Absorptionsprobleme zu vermeiden, und auch wenn das Problem in der Tat auf den Vergleich von zwei in Beziehung steht Schwimmer, es Ihnen nicht sagen, was Wert von epsilon ist richtig für das, was Sie tun, .

Wenn Sie nicht lesen Was jeder Informatiker Should Know Über Gleitkommaarithmetik , dann ist es ein guter Ausgangspunkt. Weiter als das, wenn Sie in der Genauigkeit des Ergebnisses der Division in Ihrem Beispiel interessiert sind, müssen Sie abschätzen, wie ungenau b-c durch gemacht wurde zurück Rundungsfehler, da in der Tat, wenn b-c klein ist, ein kleiner absoluter Fehler entspricht einen großen absoluten Fehler auf dem Ergebnis. Wenn Ihr Anliegen ist nur, dass die Teilung nicht Überlauf soll, dann Test (auf dem Ergebnis) richtig ist. Es gibt keinen Grund zu Test für einen Null-Teiler mit Gleitkommazahlen, die Sie gerade für Überlauf des Ergebnisses Test, der erfasst sowohl die Fälle, in denen der Divisor null ist und wo der Teiler so klein ist, wie das Ergebnis machen nicht darstellbare mit jede Präzision.

Im Hinblick auf die Ausbreitung von Rundungsfehlern existiert spezialisierte Analysatoren , die können Ihnen helfen, schätzen, weil es eine mühsame Sache ist, von Hand zu tun.

Andere Tipps

Epsilon wird verwendet, um zu bestimmen, ob zwei Zahlen unterliegen Fehler Rundung nahe genug sind zu berücksichtigen „gleich“. Beachten Sie, dass es besser Test fabs(b/c - 1) < EPS als fabs(b-c) < EPS ist, und noch besser - dank der Gestaltung von IEEE schwimmt - zu Test abs(*(int*)&b - *(int*)&c) < EPSI (wo EPSI ist einige kleine ganze Zahl)

.

Ihr Problem ist von einer anderen Natur und wahrscheinlich garantiert Testen des Ergebnisses anstatt den Eingängen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top