La norme C ++ 03 s'appuie sur la norme C90 pour ce que la norme appelle la bibliothèque C standard qui est couverte dans le projet de norme C ++ 03 (le projet de norme le plus proche du C ++ 03 est N1804 ). 1.2
Références normatives :
La bibliothèque décrite à l'article 7 de l'ISO / CEI 9899: 1990 et à l'article 7 de l'ISO / CEI 9899 / Amd.1: 1995 est ci-après appelée la bibliothèque C standard. 1)
Si nous allons dans la documentation C pour round, lround, llround sur cppreference, nous pouvons voir que round et les fonctions associées font partie de C99 et ne seront donc pas disponibles en C ++ 03 ou avant.
En C ++ 11, cela change car C ++ 11 s'appuie sur le projet de norme C99 pour la bibliothèque de normes C et fournit donc std :: round et pour les types de retour intégrés 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 ;
}
Une autre option également de C99 serait std :: trunc qui:
Calcule l'entier le plus proche dont la magnitude n'est pas supérieure à arg.
#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 ;
}
Si vous devez prendre en charge des applications non C ++ 11, votre meilleur pari serait d'utiliser le boost round, iround, lround, llround ou boost trunc .
Rouler sa propre version du tour est difficile
Faire rouler le vôtre ne vaut probablement pas la peine car plus difficile qu'il n'y paraît: arrondir le flottant à l'entier le plus proche, partie 1 , arrondir le flotteur à l'entier le plus proche, partie 2 et arrondir le flotteur à l'entier le plus proche, partie 3 explique:
Par exemple, un roll commun que votre implémentation utilise std::floor
et ajoute 0.5
ne fonctionne pas pour toutes les entrées:
double myround(double d)
{
return std::floor(d + 0.5);
}
Une entrée pour laquelle cela échouera est 0.49999999999999994
( voir en direct ).
Une autre implémentation courante consiste à convertir un type à virgule flottante en un type intégral, qui peut invoquer un comportement indéfini dans le cas où la partie intégrale ne peut pas être représentée dans le type de destination. Nous pouvons le voir dans le projet de section standard C ++ 4.9
Conversions intégrale flottante qui dit (c'est moi qui souligne ):
Une valeur d'un type à virgule flottante peut être convertie en une valeur d'un type entier. La conversion tronque; c'est-à-dire que la partie fractionnaire est jetée.Le comportement n'est pas défini si la valeur tronquée ne peut pas être représentée dans le type de destination. [...]
Par exemple:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Étant donné std::numeric_limits<unsigned int>::max()
est4294967295
alors l'appel suivant:
myround( 4294967296.5f )
provoquera un débordement, ( voir en direct ).
Nous pouvons voir à quel point cela est vraiment difficile en regardant cette réponse à la manière concise d'implémenter round () en C? qui fait référence à newlibs version du flotteur simple précision. C'est une fonction très longue pour quelque chose qui semble simple. Il semble peu probable que quiconque sans connaissance intime des implémentations en virgule flottante puisse correctement implémenter cette fonction:
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;
}
D'un autre côté, si aucune des autres solutions n'est utilisable, newlib pourrait potentiellement être une option car c'est une implémentation bien testée.
std::cout << std::fixed << std::setprecision(0) << -0.9
, par exemple.