Ich bin auf diesen Code hier gestoßen.
%Vor%Bin ich falsch zu denken, dass // 3 gefährlich ist?
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.
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:
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.
Es gibt zwei verschiedene, aber verwandte Fragen:
j
eine Ganzzahl? 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.
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 ++ .
Tags und Links c++ floating-point