Der C ++ 03-Standard stützt sich auf den C90-Standard für das, was der Standard die Standard-C-Bibliothek nennt, die im Abschnitt zum Entwurf des C ++ 03-Standards (der C ++ 03 am nächsten liegende öffentlich zugängliche Standardentwurf ist N1804 ) behandelt wird. 1.2
Normative Verweise :
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 zur C-Dokumentation für round, lround, llround on cppreference gehen , können wir sehen, dass round und verwandte Funktionen Teil von C99 sind und daher in C ++ 03 oder früher nicht verfügbar sind.
In C ++ 11 ändert sich dies, da C ++ 11 auf dem C99-Standardentwurf für die C-Standardbibliothek basiert und daher std :: round und für integrale Rückgabetypen std :: lround, std :: llround bereitstellt :
#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 auch von C99 wäre std :: trunc, die:
Berechnet die nächste Ganzzahl, deren Größe 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 Boost Round, Iround, Lround, Llround oder Boost Trunc .
Es ist schwer, eine eigene Version der Runde zu rollen
Das Rollen Ihres eigenen ist wahrscheinlich nicht die Mühe wert, da es schwieriger ist, als es aussieht: Rundungsfloat auf die nächste Ganzzahl, Teil 1 , Rundungsfloat auf die nächste Ganzzahl, Teil 2 und Rundungsfloat auf die nächste Ganzzahl, Teil 3 erklären:
Beispielsweise funktioniert eine gemeinsame Rolle, die Ihre Implementierung verwendet std::floor
und hinzufügt 0.5
, nicht für alle Eingaben:
double myround(double d)
{
return std::floor(d + 0.5);
}
Eine Eingabe, bei der dies fehlschlägt, ist 0.49999999999999994
( live sehen ).
Eine andere übliche Implementierung besteht darin, einen Gleitkommatyp in einen integralen Typ umzuwandeln, was zu undefiniertem Verhalten führen kann, wenn der integrale Teil im Zieltyp nicht dargestellt werden kann. Wir können dies aus dem Entwurf des C ++ - Standardabschnitts für 4.9
Floating-Integral-Konvertierungen ersehen, der besagt ( Hervorhebung von mir ):
Ein Wert eines Gleitkommatyps kann in einen Wert eines ganzzahligen Typs konvertiert werden. Die Konvertierung wird abgeschnitten. Das heißt, der Bruchteil wird verworfen. Das Verhalten ist undefiniert, wenn der abgeschnittene Wert im Zieltyp nicht dargestellt werden kann. [...]
Beispielsweise:
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 einen Überlauf verursachen ( live sehen ).
Wir können sehen, wie schwierig dies wirklich ist, wenn wir uns diese Antwort auf den prägnanten Weg ansehen , um round () in C zu implementieren. welche referenzierende Newlibs- Version von Single Precision Float Round. Es ist eine sehr lange Funktion für etwas, das einfach erscheint. Es ist unwahrscheinlich, dass jemand ohne genaue Kenntnisse über Gleitkommaimplementierungen diese Funktion korrekt implementieren kann:
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;
}
Wenn andererseits keine der anderen Lösungen verwendbar ist, könnte newlib möglicherweise eine Option sein, da es sich um eine gut getestete Implementierung handelt.
std::cout << std::fixed << std::setprecision(0) << -0.9
.