Ist es sicher in diesem Beispiel == on FP zu verwenden?

8

Ich bin auf diesen Code hier gestoßen.

%Vor%

Bin ich falsch zu denken, dass // 3 gefährlich ist?

    
NoSenseEtAl 21.01.2014, 01:53
quelle

3 Antworten

10

Dieser Code wird vom C ++ - Standard nicht garantiert, um wie gewünscht zu funktionieren.

Einige minderwertige Math-Bibliotheken geben keine korrekt gerundeten Werte für pow zurück, auch wenn die Eingaben ganzzahlige Werte haben und das mathematische Ergebnis genau dargestellt werden kann. sqrt kann auch einen ungenauen Wert zurückgeben, obwohl diese Funktion einfacher zu implementieren ist und weniger häufig Fehler aufweist.

Somit ist nicht garantiert, dass j genau eine ganze Zahl ist, wenn Sie es erwarten.

In einer hochwertigen Math-Bibliothek geben pow und sqrt immer korrekte Ergebnisse zurück (Null-Fehler), wenn das mathematische Ergebnis genau darstellbar ist. Wenn Sie eine gute C ++ - Implementierung haben, sollte dieser Code wie gewünscht funktionieren, bis zu den Grenzen der verwendeten Integer- und Fließkommatypen.

Verbesserung des Codes

Dieser Code hat keinen Grund, pow zu verwenden; std::pow(i, 2) sollte i*i sein. Dies führt zu einer genauen Arithmetik (bis zum Punkt des Integer-Überlaufs) und vermeidet vollständig die Frage, ob pow korrekt ist.

Das Entfernen von pow lässt nur sqrt . Wenn wir wissen, dass die Implementierung korrekte Werte zurückgibt, können wir die Verwendung von sqrt akzeptieren. Wenn nicht, können wir dies stattdessen verwenden:

%Vor%

Dieser Code basiert nur auf sqrt , um ein Ergebnis mit einer Genauigkeit von 0,5 zurückzugeben, das selbst eine minderwertige sqrt -Implementierung für sinnvolle Eingabewerte liefern sollte.

    
Eric Postpischil 21.01.2014, 02:05
quelle
1

Es gibt zwei verschiedene, aber verwandte Fragen:

  1. Ist j eine Ganzzahl?
  2. Ist j wahrscheinlich das Ergebnis einer doppelten Berechnung, deren genaues Ergebnis eine ganze Zahl wäre?

Der zitierte Code stellt die erste Frage. Es ist nicht richtig, die zweite Frage zu stellen. Mehr Kontext wäre erforderlich, um sicher zu sein, welche Frage gestellt werden sollte.

Wenn die zweite Frage gestellt werden soll, kann man sich nicht nur auf floor verlassen. Betrachten Sie eine Verdoppelung, die größer ist als 2.99999999999, aber kleiner als 3. Sie könnte das Ergebnis einer Berechnung sein, deren genauer Wert 3 wäre. Ihr Boden ist 2 und er ist um fast 1 größer als sein Boden. Sie müssten vergleichen nahe am Ergebnis von std:round liegen.

    
Patricia Shanahan 21.01.2014 11:45
quelle
0

Ich würde sagen, es ist gefährlich. Man sollte immer auf "Gleichheit" von Fließkommazahlen prüfen, indem man den Unterschied zwischen den zwei Zahlen mit einer annehmbar kleinen Zahl vergleicht, z.B.:

%Vor%

... wobei eps eine Zahl ist, die für den eigenen Zweck akzeptabel klein ist. Dieser Ansatz ist wesentlich, es sei denn, man kann garantieren, dass die Operationen exakte Ergebnisse liefern, was in einigen Fällen zutrifft (z. B. IEEE-754-konforme Systeme), aber der C ++ - Standard erfordert nicht, dass dies zutrifft. Siehe zum Beispiel plattformübergreifende Probleme mit Fließkomma-Arithmetik in C ++ .

    
Simon 21.01.2014 02:06
quelle

Tags und Links