Ich brauche eine einfache Gleitkomma-Rundungsfunktion, also:
double round(double);
round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1
ich kann finden ceil()
und floor()
in der math.h – aber nicht round()
.
Ist es in der Standard-C++-Bibliothek unter einem anderen Namen vorhanden oder fehlt es?
Anmerkung des Herausgebers: Die folgende Antwort bietet eine vereinfachte Lösung, die mehrere Implementierungsfehler enthält (eine vollständige Erklärung finden Sie in der Antwort von Shafik Yaghmour). Beachten Sie, dass C++11 enthält std::round
, std::lround
und std::llround
als eingebaute bereits.
In der C++98-Standardbibliothek gibt es kein round(). Du kannst aber auch selbst einen schreiben. Das Folgende ist eine Implementierung von Runde-halb-auf:
double round(double d)
{
return floor(d + 0.5);
}
Der wahrscheinliche Grund dafür, dass es in der C++98-Standardbibliothek keine Round-Funktion gibt, ist, dass sie tatsächlich auf verschiedene Arten implementiert werden kann. Das obige ist ein gängiger Weg, aber es gibt andere wie z rund-auf-gerade, was weniger voreingenommen und im Allgemeinen besser ist, wenn Sie viel runden; Es ist jedoch etwas komplexer zu implementieren.
Boost bietet einen einfachen Satz von Rundungsfunktionen.
#include <boost/math/special_functions/round.hpp>
double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer
Weitere Informationen finden Sie unter Boost-Dokumentation.
Bearbeiten: Seit C++11 gibt es std::round
, std::lround
und std::llround
.
Der C++03-Standard stützt sich auf den C90-Standard für das, was der Standard als bezeichnet Standard-C-Bibliothek die im Entwurf des C++03-Standards behandelt wird (N1804 ist ein öffentlich verfügbarer Standardentwurf, der C++03 am nächsten kommt) Sektion 1.2
Normative Verweisungen:
Die in Abschnitt 7 von ISO/IEC 9899:1990 und Abschnitt 7 von ISO/IEC 9899/Amd.1:1995 beschriebene Bibliothek wird im Folgenden als Standard-C-Bibliothek bezeichnet.1)
Wenn wir in die gehen C-Dokumentation für round, lround, llround auf cpreference wir können das sehen runden und verwandte Funktionen sind Teil von C99 und wird daher in C++03 oder früher nicht verfügbar sein.
In C++11 ändert sich dies, da C++11 auf dem Entwurf des C99-Standards für basiert C-Standardbibliothek und bietet daher std::round und für ganzzahlige Rückgabetypen std::lround, std::llround :
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
Eine andere Option wäre auch ab C99 std::trunc welcher:
Berechnet die nächste ganze Zahl, die nicht größer als arg ist.
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
Wenn Sie Nicht-C++11-Anwendungen unterstützen müssen, verwenden Sie am besten Runde, iround, lround, llround verstärken oder Boost-Trunk.
Es ist schwierig, seine eigene Version von Round zu rollen
Selber rollen lohnt sich da wohl nicht Schwieriger als es aussieht: Float auf die nächste Ganzzahl runden, Teil 1, Float auf die nächste Ganzzahl runden, Teil 2 und Float auf die nächste Ganzzahl runden, Teil 3 erklären:
Zum Beispiel eine gemeinsame Rolle, die Ihre Implementierung verwendet std::floor
und hinzufügen 0.5
funktioniert nicht bei allen Eingängen:
double myround(double d)
{
return std::floor(d + 0.5);
}
Eine Eingabe, für die dies fehlschlägt, ist 0.49999999999999994
(live sehen).
Eine weitere gängige Implementierung besteht darin, einen Gleitkommatyp in einen ganzzahligen Typ umzuwandeln, der ein undefiniertes Verhalten hervorrufen kann, falls der ganzzahlige Teil nicht im Zieltyp dargestellt werden kann. Wir können dies aus dem Entwurf des C++-Standardabschnitts ersehen 4.9
Floating-Integral-Konvertierungen was sagt (Betonung von mir):
Ein Prvalue vom Typ Gleitkomma kann in einen Prvalue vom Typ Integer konvertiert werden. Die Konvertierung wird abgeschnitten; das heißt, der Bruchteil wird verworfen. Das Verhalten ist undefiniert, wenn der abgeschnittene Wert nicht im Zieltyp dargestellt werden kann.[…]
Zum Beispiel:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Gegeben std::numeric_limits<unsigned int>::max()
ist 4294967295
dann folgender Aufruf:
myround( 4294967296.5f )
wird Überlauf verursachen, (live sehen).
Wir können sehen, wie schwierig das wirklich ist, wenn wir uns diese Antwort auf Concise way to implement round() in C? welche Referenzierung neuelibs Version von Single Precision Float Round. Es ist eine sehr lange Funktion für etwas, das einfach erscheint. Es scheint unwahrscheinlich, dass jemand ohne genaue Kenntnisse von Gleitkommaimplementierungen diese Funktion korrekt implementieren könnte:
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
Andererseits, wenn keine der anderen Lösungen verwendbar sind neuelib könnte möglicherweise eine Option sein, da es sich um eine gut getestete Implementierung handelt.
Es kann erwähnenswert sein, dass Sie, wenn Sie ein ganzzahliges Ergebnis aus der Rundung erhalten möchten, es weder durch die Obergrenze noch durch die Untergrenze leiten müssen. Dh,
int round_int( double r ) {
return (r > 0.0) ? (r + 0.5) : (r - 0.5);
}
Es ist seit C++11 in cmath verfügbar (gemäß http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf)
#include <cmath>
#include <iostream>
int main(int argc, char** argv) {
std::cout << "round(0.5):\t" << round(0.5) << std::endl;
std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
std::cout << "round(1.4):\t" << round(1.4) << std::endl;
std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
std::cout << "round(1.6):\t" << round(1.6) << std::endl;
std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
return 0;
}
Ausgabe:
round(0.5): 1
round(-0.5): -1
round(1.4): 1
round(-1.4): -1
round(1.6): 2
round(-1.6): -2
Es wird normalerweise als implementiert floor(value + 0.5)
.
Bearbeiten: und es wird wahrscheinlich nicht rund genannt, da es mindestens drei mir bekannte Rundungsalgorithmen gibt: Runden auf Null, Runden auf die nächste ganze Zahl und Runden des Bankers. Sie fragen nach dem Runden auf die nächste ganze Zahl.
Es gibt 2 Probleme, die wir betrachten:
- Rundungskonvertierungen
- Typkonvertierung.
Rundungskonvertierungen bedeuten Rundung ± Float/Double zum nächsten Floor/Ceil Float/Double. Vielleicht endet Ihr Problem hier. Aber wenn erwartet wird, dass Sie Int/Long zurückgeben, müssen Sie eine Typkonvertierung durchführen, und daher könnte das Problem “Overflow” Ihre Lösung treffen. Also, überprüfen Sie Ihre Funktion auf Fehler
long round(double x) {
assert(x >= LONG_MIN-0.5);
assert(x <= LONG_MAX+0.5);
if (x >= 0)
return (long) (x+0.5);
return (long) (x-0.5);
}
#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
von : http://www.cs.tut.fi/~jkorpela/round.html
Wenn Sie die Zahl nur als gerundete Zahl ausgeben möchten, können Sie dies anscheinend tun
std::cout << std::fixed << std::setprecision(0) << -0.9
zum Beispiel.– Frank
17. Februar 2011 um 18:05 Uhr
Schützen Sie dies … Neue Benutzer mit brillanten neuen Rundungsschemata sollten zuerst die vorhandenen Antworten lesen.
– Shog9
18. Februar 2011 um 20:33 Uhr
round
ist seit C++11 in verfügbar<cmath>
. Wenn Sie sich in Microsoft Visual Studio befinden, fehlt es leider immer noch: connect.microsoft.com/VisualStudio/feedback/details/775474/…– Alessandro Jacobson
5. April 2013 um 8:29 Uhr
Wie ich in meiner Antwort feststelle, rollen Sie Ihre eigenen
round
hat viele Vorbehalte. Vor C++11 stützte sich der Standard auf C90, das nicht enthalten warround
. C ++ 11 basiert auf C99, das dies hatround
aber auch, wie ich angemerkt habetrunc
die unterschiedliche Eigenschaften hat und je nach Anwendung geeigneter sein kann. Die meisten Antworten scheinen auch zu ignorieren, dass ein Benutzer möglicherweise einen ganzzahligen Typ zurückgeben möchte, der noch mehr Probleme hat.– Shafik Yaghmour
23. Juni 2014 um 13:39 Uhr
@uvts_cvs Dies scheint kein Problem mit der neuesten Version von Visual Studio zu sein. live sehen.
– Shafik Yaghmour
23. Juni 2014 um 13:49 Uhr