Die Unterschiede liegen im zurückgegebenen Wert, der meiner Meinung nach Eingaben zum Brechen von Unentschieden liefert, wie zum Beispiel diesen Code :
int main()
{
std::cout.precision(100);
double input = std::nextafter(0.05, 0.0) / 0.1;
double x1 = floor(0.5 + input);
double x2 = round(input);
std::cout << x1 << std::endl;
std::cout << x2 << std::endl;
}
welche Ausgänge:
1
0
Aber am Ende sind es nur unterschiedliche Ergebnisse, man wählt das bevorzugte. Ich sehe viele "alte" C / C ++ - Programme, die floor(0.5 + input)
anstelle von verwenden round(input)
.
Gibt es einen historischen Grund? Günstigstes auf der CPU?
Antworten:
std::round
wird in C ++ 11 eingeführt. Vorher war nurstd::floor
verfügbar, also verwendeten Programmierer es.quelle
Es gibt überhaupt keinen historischen Grund. Diese Art von Abweichung gibt es seit Jahr. Leute tun dies, wenn sie sich sehr, sehr ungezogen fühlen. Es ist ein Missbrauch der Gleitkomma-Arithmetik, und viele erfahrene professionelle Programmierer fallen darauf herein. Sogar die Java-Bods haben bis zur Version 1.7 gearbeitet. Lustige Typen.
Meine Vermutung ist, dass eine anständige sofort einsatzbereite deutsche Rundungsfunktion erst in C ++ 11 offiziell verfügbar war (obwohl C sie in C99 erhalten hat), aber das ist wirklich keine Entschuldigung für die Übernahme der sogenannten Alternative.
Hier ist die Sache:
floor(0.5 + input)
stellt nicht immer das gleiche Ergebnis wie der entsprechendestd::round
Aufruf wieder her!Der Grund ist ziemlich subtil: Der Grenzwert für eine deutsche Rundung,
a.5
für eine ganze Zahl,a
ist durch eine zufällige Eigenschaft des Universums eine dyadische Rationalität . Da dies genau in einem IEEE754-Gleitkomma bis zur 52. Potenz von 2 dargestellt werden kann und danach das Runden ohnehin ein No-Op ist,std::round
funktioniert es immer richtig. Weitere Gleitkommaschemata finden Sie in der Dokumentation.Das Hinzufügen
0.5
zu adouble
kann jedoch zu Ungenauigkeiten führen, die bei einigen Werten zu einem leichten Unter- oder Überschwingen führen. Wenn Sie darüber nachdenken, führt das Addieren von zweidouble
Werten - das ist der Beginn unwissentlicher Denary-Konvertierungen - und das Anwenden einer Funktion, die eine sehr starke Funktion der Eingabe ist (z. B. eine Rundungsfunktion), zwangsläufig zu Tränen.Tu es nicht .
Referenz: Warum gibt Math.round (0.49999999999999994) 1 zurück?
quelle
nearbyint()
ist normalerweise eine bessere Wahl alsround()
, danearbyint
der aktuelle Rundungsmodus anstelle des funky Tiebreak von Null entfernt verwendet wirdround()
(für den x86 nicht einmal Hardware-Unterstützung bietet, obwohl ARM dies tut). Beide wurden in C ++ 11 zu C ++ hinzugefügt.Ich denke, hier irren Sie:
Das ist nicht der Fall. Sie müssen das richtige Rundungsschema für die Domain auswählen . In einer Finanzanwendung werden Sie nach den Regeln des Bankiers runden (übrigens nicht mit float). Beim Abtasten
static_cast<int>(floor(f + .5))
ergibt das Aufrunden mit weniger Abtastrauschen jedoch den Dynamikbereich. Wenn Sie Pixel ausrichten, dh eine Position in Bildschirmkoordinaten konvertieren, erhalten Sie mit einer anderen Rundungsmethode Löcher, Lücken und andere Artefakte.quelle
Ein einfacher Grund könnte sein, dass es verschiedene Methoden zum Runden von Zahlen gibt. Wenn Sie also die verwendete Methode nicht kennen, können Sie unterschiedliche Ergebnisse erzielen.
Mit floor () können Sie mit den Ergebnissen übereinstimmen. Wenn der Float 0,5 oder höher ist, wird durch Hinzufügen bis zum nächsten int gestoßen. Aber .49999 lässt nur die Dezimalstelle fallen.
quelle
round()
tut.floor(x + 0.5)
tut.nearbyint(x)
verwenden eine vernünftige (bis zur nächsten geraden) Rundung, vorausgesetzt, Sie haben nicht mit der Gleitkommaumgebung herumgespielt.Viele Programmierer passen Redewendungen an, die sie beim Programmieren mit anderen Sprachen gelernt haben. Nicht alle Sprachen haben eine
round()
Funktion, und in diesen Sprachen ist es normal, siefloor(x + 0.5)
als Ersatz zu verwenden. Wenn diese Programmierer anfangen, C ++ zu verwenden, stellen sie nicht immer fest, dass es eine integrierte Funktion gibtround()
, sondern verwenden weiterhin den Stil, den sie gewohnt sind.Mit anderen Worten, nur weil Sie viel Code sehen, der etwas bewirkt, heißt das nicht, dass es einen guten Grund dafür gibt. Beispiele hierfür finden Sie in jeder Programmiersprache. Denken Sie an das Störgesetz :
quelle