round () pour float dans C ++

J’ai besoin d’une fonction simple d’arrondi en virgule flottante, donc:

double round(double); round(0.1) = 0 round(-0.1) = 0 round(-0.9) = -1 

Je peux trouver ceil() et floor() dans le math.h – mais pas round() .

Est-il présent dans la bibliothèque C ++ standard sous un autre nom, ou est-ce qu’il manque?

Il n’y a pas de round () dans la bibliothèque standard C ++ 98. Vous pouvez cependant en écrire un vous-même. Ce qui suit est une implémentation de round-half :

 double round(double d) { return floor(d + 0.5); } 

La raison probable pour laquelle il n’existe pas de fonction ronde dans la bibliothèque standard C ++ 98 est qu’elle peut en fait être implémentée de différentes manières. Ce qui précède est une façon courante, mais il y en a d’autres, comme l’ aller-retour , qui est moins biaisé et généralement meilleur si vous devez arrondir beaucoup; c’est un peu plus complexe à mettre en œuvre.

Boost offre un ensemble simple de fonctions d’arrondi.

 #include  double a = boost::math::round(1.5); // Yields 2.0 int b = boost::math::iround(1.5); // Yields 2 as an integer 

Pour plus d’informations, consultez la documentation Boost .

Edit : Depuis C ++ 11, il existe std::round , std::lround et std::llround .

La norme C ++ 03 s’appuie sur la norme C90 pour ce que la norme appelle la bibliothèque C standard, qui est traitée dans le projet de norme C ++ 03 (la version préliminaire la plus proche de C ++ 03 est N1804 ) section 1.2 Références normatives :

La bibliothèque décrite dans les articles 7 de la norme ISO / IEC 9899: 1990 et 7 de la norme ISO / IEC 9899 / Amd.1: 1995 est appelée ci-après la bibliothèque standard C. 1)

Si nous allons à la documentation C pour round, lround, llround sur cppreference, nous pouvons voir que les fonctions round et related font partie de C99 et ne seront donc pas disponibles dans C ++ 03 ou avant.

En C ++ 11, cela change car C ++ 11 s’appuie sur le projet de norme C99 pour la bibliothèque standard C et fournit donc std :: round et pour les types de retour intégral std :: lround, std :: llround :

 #include  #include  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 le plus petit entier non supérieur à arg.

 #include  #include  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 avez besoin de prendre en charge des applications non C ++ 11, le mieux est d'utiliser boost round, iround, lround, llround ou boost trunc .

Rouler votre propre version de round est difficile

Le fait de rouler vous-même ne vaut probablement pas la peine d'être aussi difficile que cela en a l'air: arrondir le flottant au nombre entier le plus proche, la partie 2 et l' arrondi au nombre entier le plus proche, la partie 3 expliquent:

Par exemple, un déploiement commun de votre implémentation à l'aide de std::floor et l'ajout de 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 le live ).

Une autre implémentation commune consiste à transtyper 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 à partir du projet de section standard C ++ 4.9 Conversions intégrales flottantes qui dit ( emphase mienne ):

Une valeur de type virgule flottante peut être convertie en une valeur de type entier. La conversion est tronquée. c'est-à-dire que la partie fractionnaire est rejeté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( static_cast( f ) ) ; } 

Étant donné std::numeric_limits::max() est 4294967295 puis l'appel suivant:

 myround( 4294967296.5f ) 

provoquera un débordement, ( voyez-le en direct ).

Nous pouvons voir à quel point c'est difficile en regardant cette réponse à la manière concise d'implémenter round () dans C? qui fait référence à la version newlibs de la précision simple float round. C'est une fonction très longue pour quelque chose qui semble simple. Il semble peu probable qu'une personne sans connaissance approfondie des implémentations en virgule flottante puisse implémenter correctement 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 être une option car il s'agit d'une implémentation bien testée.

Il peut être utile de noter que si vous voulez un résultat entier de l’arrondi, vous n’avez pas besoin de le faire passer par le plafond ou le sol. C’est à dire,

 int round_int( double r ) { return (r > 0.0) ? (r + 0.5) : (r - 0.5); } 

Il est disponible depuis C ++ 11 dans cmath (selon http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf )

 #include  #include  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; } 

Sortie:

 round(0.5): 1 round(-0.5): -1 round(1.4): 1 round(-1.4): -1 round(1.6): 2 round(-1.6): -2 

Il est généralement implémenté comme floor(value + 0.5) .

Edit: et ce n’est probablement pas appelé car il y a au moins trois algorithmes d’arrondis que je connais: arrondis à zéro, arrondis à l’entier le plus proche et arrondi au banquier. Vous demandez le nombre entier le plus proche.

Il y a 2 problèmes que nous examinons:

  1. conversions d’arrondi
  2. conversion de type.

Les conversions d’arrondi signifient un arrondi ± flottant / double au plancher / plafond le plus proche flottant / double. Peut-être que votre problème se termine ici. Mais si vous êtes censé retourner Int / Long, vous devez effectuer une conversion de type. Par conséquent, le problème de “dépassement” peut toucher votre solution. SO, faire une vérification de l’erreur dans votre fonction

 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)) 

à partir de: http://www.cs.tut.fi/~jkorpela/round.html

Un certain type d’arrondi est également implémenté dans Boost:

 #include  #include  template T round2(const S& x) { typedef boost::numeric::conversion_traits Traits; typedef boost::numeric::def_overflow_handler OverflowHandler; typedef boost::numeric::RoundEven Rounder; typedef boost::numeric::converter Converter; return Converter::convert(x); } int main() { std::cout << round2(0.1) << ' ' << round2(-0.1) << ' ' << round2(-0.9) << std::endl; } 

Notez que cela ne fonctionne que si vous faites une conversion à un nombre entier.

Vous pouvez arrondir la précision à n chiffres avec:

 double round( double x ) { const double sd = 1000; //for accuracy to 3 decimal places return int(x*sd + (x<0? -0.5 : 0.5))/sd; } 

Si vous voulez finalement convertir la double sortie de votre fonction round() en int , les solutions acceptées de cette question ressembleront à:

 int roundint(double r) { return (int)((r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5)); } 

Cette horloge tourne autour de 8,88 ns sur ma machine lorsque les valeurs sont uniformément aléatoires.

Ce qui suit est fonctionnellement équivalent, pour autant que je sache, mais les horloges à 2,48 ns sur ma machine, pour un avantage de performance significatif:

 int roundint (double r) { int tmp = static_cast (r); tmp += (r-tmp>=.5) - (r-tmp<=-.5); return tmp; } 

Parmi les raisons des meilleures performances, citons le saut de twig.

Attention au floor(x+0.5) . Voici ce qui peut arriver pour les nombres impairs dans l’intervalle [2 ^ 52,2 ^ 53]:

 -bash-3.2$ cat >test-round.c < #include  int main() { double x=5000000000000001.0; double y=round(x); double z=floor(x+0.5); printf(" x =%f\n",x); printf("round(x) =%f\n",y); printf("floor(x+0.5)=%f\n",z); return 0; } END -bash-3.2$ gcc test-round.c -bash-3.2$ ./a.out x =5000000000000001.000000 round(x) =5000000000000001.000000 floor(x+0.5)=5000000000000002.000000 

Ceci est http://bugs.squeak.org/view.php?id=7134 . Utilisez une solution comme celle de @konik.

Ma propre version robuste serait quelque chose comme:

 double round(double x) { double truncated,roundedFraction; double fraction = modf(x, &truncated); modf(2.0*fraction, &roundedFraction); return truncated + roundedFraction; } 

Une autre raison pour éviter le plancher (x + 0.5) est donnée ici .

Il n’y a pas besoin d’implémenter quoi que ce soit, donc je ne sais pas pourquoi tant de réponses impliquent des définitions, des fonctions ou des méthodes.

En C99

Nous avons les éléments suivants et les en-têtes pour les macros génériques.

 #include  double round (double x); float roundf (float x); long double roundl (long double x); 

Si vous ne pouvez pas comstackr cela, vous avez probablement laissé de côté la bibliothèque mathématique. Une commande similaire à celle-ci fonctionne sur tous les compilateurs C que j’ai (plusieurs).

 gcc -lm -std=c99 ... 

En C ++ 11

Nous avons les surcharges suivantes et supplémentaires dans #include qui reposent sur la virgule flottante à double précision IEEE.

 #include  double round (double x); float round (float x); long double round (long double x); double round (T x); 

Il y a aussi des équivalents dans l’espace de noms std .

Si vous ne pouvez pas comstackr cela, vous utilisez peut-être la compilation C au lieu de C ++. La commande de base suivante ne génère ni erreurs ni avertissements avec g ++ 6.3.1, x86_64-w64-mingw32-g ++ 6.3.0, clang-x86_64 ++ 3.8.0 et Visual C ++ 2015 Community.

 g++ -std=c++11 -Wall 

Avec division ordinale

Lorsque vous divisez deux nombres ordinaux, où T est court, int, long ou un autre ordinal, l’expression d’arrondi est la suivante.

 T roundedQuotient = (2 * integerNumerator + 1) / (2 * integerDenominator); 

Précision

Il ne fait aucun doute que des inexactitudes d’aspect étrange apparaissent dans les opérations à virgule flottante, mais cela ne se produit que lorsque les nombres apparaissent et a peu à voir avec l’arrondissement.

La source n’est pas simplement le nombre de chiffres significatifs dans la mantisse de la représentation IEEE d’un nombre à virgule flottante, elle est liée à notre pensée décimale en tant qu’êtres humains.

Dix est le produit de cinq et deux et 5 et 2 sont relativement premiers. Par conséquent, les normes à virgule flottante IEEE ne peuvent pas être représentées parfaitement comme des nombres décimaux pour toutes les représentations numériques binarys.

Ce n’est pas un problème avec les algorithmes d’arrondi. C’est la réalité mathématique qui doit être prise en compte lors de la sélection des types et de la conception des calculs, de la saisie des données et de l’affichage des nombres. Si une application affiche les chiffres qui montrent ces problèmes de conversion décimal-binary, l’application exprime visuellement la précision qui n’existe pas dans la réalité numérique et devrait être modifiée.

De nos jours, l’utilisation d’un compilateur C ++ 11 comprenant une bibliothèque mathématique C99 / C ++ 11 ne devrait pas poser de problème. Mais alors la question devient: quelle fonction d’arrondi choisissez-vous?

C99 / C ++ 11 round() n’est souvent pas la fonction d’arrondi souhaitée . Il utilise un mode d’arrondi funky qui arrondit à 0 en tant que tie-break sur les cas à mi-chemin ( +-xxx.5000 ). Si vous voulez spécifiquement ce mode d’arrondi, ou si vous visez une implémentation C ++ où round() est plus rapide que rint() , alors utilisez-le (ou imitez son comportement avec l’une des autres réponses à cette question qui l’a pris valeur et reproduit soigneusement ce comportement d’arrondi spécifique.)

round() est différent de l’arrondi IEEE754 par défaut au mode le plus proche, même en cas d’égalité . Le plus proche-même évite un biais statistique dans la magnitude moyenne des nombres, mais privilégie les nombres pairs.

Il y a deux fonctions d’arrondi de bibliothèques mathématiques qui utilisent le mode d’arrondi par défaut actuel: std::nearbyint() et std::rint() , toutes deux ajoutées dans C99 / C ++ 11, elles sont donc disponibles à tout moment std::round() est. La seule différence est que nearbyint ne déclenche jamais FE_INEXACT.

Préférez rint() pour des raisons de performances : gcc et clang les deux plus facilement, mais gcc ne les enchaîne jamais nearbyint() (même avec -ffast-math )


gcc / clang pour x86-64 et AArch64

J’ai mis des fonctions de test sur Comstackr Explorer de Matt Godbolt , où vous pouvez voir les sorties source + asm (pour plusieurs compilateurs). Pour en savoir plus sur la lecture du compilateur, reportez-vous à cette question et à la discussion de Matt CppCon2017: «Qu’est-ce que mon compilateur a fait pour moi récemment? Dénuder le couvercle du compilateur » ,

En code FP, c’est généralement un gros gain pour intégrer de petites fonctions. En particulier sur les systèmes autres que Windows, pour lesquels la convention d’appel standard ne comporte pas de registres préservant les appels, de sorte que le compilateur ne peut conserver aucune valeur FP dans les registres XMM lors d’un call . Donc, même si vous ne connaissez pas vraiment asm, vous pouvez toujours voir facilement s’il s’agit simplement d’un appel à la fonction de bibliothèque ou si cela correspond à une ou deux instructions mathématiques. Tout ce qui correspond à une ou deux instructions est préférable à un appel de fonction (pour cette tâche particulière sur x86 ou ARM).

Sur x86, tout ce qui est intégré à SSE4.1 roundsd peut roundsd -vectoriser avec SSE4.1 roundpd (ou AVX vroundpd ). (Les conversions entières FP-> sont également disponibles sous forme SIMD compressée, sauf pour FP-> Entier 64 bits qui nécessite AVX512.)

  • std::nearbyint() :

    • Clash x86: se connecte à un seul insn avec -msse4.1 .
    • x86 gcc: accède à un seul insn uniquement avec -msse4.1 -ffast-math , et uniquement sur gcc 5.4 et les -msse4.1 -ffast-math antérieures . Plus tard, gcc ne l’a jamais intégré (peut-être qu’ils ne se sont pas rendu compte qu’un des bits immédiats pouvait supprimer l’exception inexacte? C’est ce que Clang utilise, mais les anciennes versions de gcc utilisent le même immédiat que rint lorsqu’il l’ rint )
    • AArch64 gcc6.3: insère un seul insn par défaut.
  • std::rint :

    • clavardement x86: accède à un seul insn avec -msse4.1
    • x86 gcc7: insère un insn unique avec -msse4.1 . (Sans SSE4.1, en ligne avec plusieurs instructions)
    • x86 gcc6.x et versions antérieures: en ligne avec un seul insn avec -ffast-math -msse4.1 .
    • AArch64 gcc: inline à un seul insn par défaut
  • std::round :

    • x86 clang: ne pas en ligne
    • x86 gcc: correspond à plusieurs instructions avec -ffast-math -msse4.1 , nécessitant deux constantes vectorielles.
    • AArch64 gcc: s’aligne sur une seule instruction (prise en charge du matériel pour ce mode d’arrondi, ainsi que la valeur par défaut de l’IEEE et la plupart des autres).
  • std::floor / std::ceil / std::trunc

    • clavardement x86: accède à un seul insn avec -msse4.1
    • x86 gcc7.x: insère dans un seul insn avec -msse4.1
    • x86 gcc6.x et versions antérieures: inline à un seul insn avec -ffast-math -msse4.1
    • AArch64 gcc: inlines par défaut à une seule instruction

Arrondi à int / long / long long :

Vous avez deux options ici: utilisez lrint (comme rint mais retourne long , ou long long pour llrint ), ou utilisez une fonction d’arrondi FP-> FP puis convertissez en un type entier de manière normale (avec troncature). Certains compilateurs optimisent un moyen mieux que l’autre.

 long l = lrint(x); int i = (int)rint(x); 

Notez que int i = lrint(x) convertit d’abord float ou double -> long , puis tronque le nombre entier à int . Cela fait une différence pour les entiers hors plage: Comportement indéfini en C ++, mais bien défini pour les instructions x86 FP -> int (que le compilateur émettra à moins de voir l’UB au moment de la compilation tout en faisant une propagation constante) autorisé à faire du code qui casse s’il est jamais exécuté).

Sur x86, une conversion FP-> integer qui déborde le nombre entier produit INT_MIN ou LLONG_MIN (un modèle binary de 0x8000000 ou l’équivalent 64 bits, avec uniquement le jeu de bits). Intel appelle cela la valeur “entier indéfini”. (Voir l’entrée manuelle cvttsd2si , l’instruction SSE2 qui convertit (avec troncature) le double scalaire en entier signé. Il est disponible avec une destination entière de 32 bits ou 64 bits (en mode 64 bits uniquement). Il y a aussi un cvtsd2si mode d’arrondi courant), ce que nous aimerions que le compilateur émette, mais malheureusement, gcc et clang ne le feront pas sans -ffast-math .

Méfiez-vous également que FP à / de unsigned int / long est moins efficace sur x86 (sans AVX512). La conversion en version 32 bits non signée sur une machine 64 bits est plutôt économique. il suffit de convertir en 64 bits signés et tronqués. Mais sinon, c’est beaucoup plus lent.

  • x86 clang avec / without -ffast-math -msse4.1 : (int/long)rint rint inline à roundsd / cvttsd2si . (optimisation manquée à cvtsd2si ). lrint ne correspond pas du tout.

  • x86 gcc6.x et versions antérieures sans -ffast-math :

  • x86 gcc7 sans -ffast-math : (int/long)rint arrondit et convertit séparément (avec 2 instructions au total de SSE4.1 est activé, sinon avec un tas de code pour roundsd sans roundsd ). lrint pas.
  • x86 gcc avec -ffast-math : tous les moyens sont cvtsd2si à cvtsd2si (optimal) , pas besoin de SSE4.1.

  • AArch64 gcc6.3 sans -ffast-math : (int/long)rint rint dans 2 instructions. lrint pas

  • AArch64 gcc6.3 avec -ffast-math : (int/long)rint comstack en un appel à lrint . lrint pas. Cela peut être une optimisation manquée à moins que les deux instructions que nous recevons sans -ffast-math soient très lentes.

Fonction double round(double) avec l’utilisation de la fonction modf :

 double round(double x) { using namespace std; if ((numeric_limits::max() - 0.5) <= x) return numeric_limits::max(); if ((-1*std::numeric_limits::max() + 0.5) > x) return (-1*std::numeric_limits::max()); double intpart; double fractpart = modf(x, &intpart); if (fractpart >= 0.5) return (intpart + 1); else if (fractpart >= -0.5) return intpart; else return (intpart - 1); } 

Pour être propre à la compilation, inclut “math.h” et “limites” sont nécessaires. La fonction fonctionne selon un schéma d’arrondi suivant:

  • tour de 5.0 est 5.0
  • ronde de 3,8 est de 4,0
  • tour de 2.3 est 2.0
  • tour de 1.5 est 2.0
  • tour de 0.501 est 1.0
  • tour de 0.5 est 1.0
  • tour de 0.499 est 0.0
  • round of 0.01 is 0.0
  • tour de 0.0 est 0.0
  • tour de -0,01 est -0,0
  • tour de -0,499 est -0,0
  • tour de -0.5 est -0.0
  • round de -0.501 est -1.0
  • tour de -1.5 est -1.0
  • round of -2.3 is -2.0
  • tour de -3,8 est -4,0
  • tour de -5,0 est de -5,0

Si vous devez être capable de comstackr du code dans des environnements qui prennent en charge le standard C ++ 11, mais également pouvoir comstackr ce même code dans des environnements qui ne le supportent pas, vous pouvez utiliser une macro de fonction pour choisir entre std :: round () et une fonction personnalisée pour chaque système. Il suffit de transmettre -DCPP11 ou /DCPP11 au compilateur compatible C ++ 11 (ou d’utiliser ses macros de version intégrées) et de créer un en-tête comme celui-ci:

 // File: rounding.h #include  #ifdef CPP11 #define ROUND(x) std::round(x) #else /* CPP11 */ inline double myRound(double x) { return (x >= 0.0 ? std::floor(x + 0.5) : std::ceil(x - 0.5)); } #define ROUND(x) myRound(x) #endif /* CPP11 */ 

Pour un exemple rapide, voir http://ideone.com/zal709 .

Cela correspond approximativement à std :: round () dans les environnements qui ne sont pas compatibles avec C ++ 11, y compris la préservation du bit de signe pour -0.0. It may cause a slight performance hit, however, and will likely have issues with rounding certain known “problem” floating-point values such as 0.49999999999999994 or similar values.

Alternatively, if you have access to a C++11-compliant comstackr, you could just grab std::round() from its header, and use it to make your own header that defines the function if it’s not already defined. Note that this may not be an optimal solution, however, especially if you need to comstack for multiple platforms.

Based on Kalaxy’s response, the following is a templated solution that rounds any floating point number to the nearest integer type based on natural rounding. It also throws an error in debug mode if the value is out of range of the integer type, thereby serving roughly as a viable library function.

  // round a floating point number to the nearest integer template  int Round(Arg arg) { #ifndef NDEBUG // check that the argument can be rounded given the return type: if ( (Arg)std::numeric_limits::max() < arg + (Arg) 0.5) || (Arg)std::numeric_limits::lowest() > arg - (Arg) 0.5) ) { throw std::overflow_error("out of bounds"); } #endif return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5); } 

As pointed out in comments and other answers, the ISO C++ standard library did not add round() until ISO C++11, when this function was pulled in by reference to the ISO C99 standard math library.

For positive operands in [½, ub ] round(x) == floor (x + 0.5) , where ub is 2 23 for float when mapped to IEEE-754 (2008) binary32 , and 2 52 for double when it is mapped to IEEE-754 (2008) binary64 . The numbers 23 and 52 correspond to the number of stored mantissa bits in these two floating-point formats. For positive operands in [+0, ½) round(x) == 0 , and for positive operands in ( ub , +∞] round(x) == x . As the function is symmesortingc about the x-axis, negative arguments x can be handled according to round(-x) == -round(x) .

This leads to the compact code below. It comstacks into a reasonable number of machine instructions across various platforms. I observed the most compact code on GPUs, where my_roundf() requires about a dozen instructions. Depending on processor architecture and toolchain, this floating-point based approach could be either faster or slower than the integer-based implementation from newlib referenced in a different answer .

I tested my_roundf() exhaustively against the newlib roundf() implementation using Intel comstackr version 13, with both /fp:ssortingct and /fp:fast . I also checked that the newlib version matches the roundf() in the mathimf library of the Intel comstackr. Exhaustive testing is not possible for double-precision round() , however the code is structurally identical to the single-precision implementation.

 #include  #include  #include  #include  #include  float my_roundf (float x) { const float half = 0.5f; const float one = 2 * half; const float lbound = half; const float ubound = 1L << 23; float a, f, r, s, t; s = (x < 0) ? (-one) : one; a = x * s; t = (a < lbound) ? x : s; f = (a < lbound) ? 0 : floorf (a + half); r = (a > ubound) ? x : (t * f); return r; } double my_round (double x) { const double half = 0.5; const double one = 2 * half; const double lbound = half; const double ubound = 1ULL << 52; double a, f, r, s, t; s = (x < 0) ? (-one) : one; a = x * s; t = (a < lbound) ? x : s; f = (a < lbound) ? 0 : floor (a + half); r = (a > ubound) ? x : (t * f); return r; } uint32_t float_as_uint (float a) { uint32_t r; memcpy (&r, &a, sizeof(r)); return r; } float uint_as_float (uint32_t a) { float r; memcpy (&r, &a, sizeof(r)); return r; } float newlib_roundf (float x) { uint32_t w; int exponent_less_127; w = float_as_uint(x); /* Extract exponent field. */ exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127; if (exponent_less_127 < 23) { if (exponent_less_127 < 0) { /* Extract sign bit. */ w &= 0x80000000; if (exponent_less_127 == -1) { /* Result is +1.0 or -1.0. */ w |= ((uint32_t)127 << 23); } } else { uint32_t 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 so raise FE_INVALID by adding */ return x + x; } else { return x; } } x = uint_as_float (w); return x; } int main (void) { uint32_t argi, resi, refi; float arg, res, ref; argi = 0; do { arg = uint_as_float (argi); ref = newlib_roundf (arg); res = my_roundf (arg); resi = float_as_uint (res); refi = float_as_uint (ref); if (resi != refi) { // check for identical bit pattern printf ("!!!! arg=%08x res=%08x ref=%08x\n", argi, resi, refi); return EXIT_FAILURE; } argi++; } while (argi); return EXIT_SUCCESS; } 

I use the following implementation of round in asm for x86 architecture and MS VS specific C++:

 __forceinline int Round(const double v) { int r; __asm { FLD v FISTP r FWAIT }; return r; } 

UPD: to return double value

 __forceinline double dround(const double v) { double r; __asm { FLD v FRNDINT FSTP r FWAIT }; return r; } 

Sortie:

 dround(0.1): 0.000000000000000 dround(-0.1): -0.000000000000000 dround(0.9): 1.000000000000000 dround(-0.9): -1.000000000000000 dround(1.1): 1.000000000000000 dround(-1.1): -1.000000000000000 dround(0.49999999999999994): 0.000000000000000 dround(-0.49999999999999994): -0.000000000000000 dround(0.5): 0.000000000000000 dround(-0.5): -0.000000000000000 
 // Convert the float to a ssortingng // We might use ssortingngstream, but it looks like it truncates the float to only //5 decimal points (maybe that's what you want anyway =P) float MyFloat = 5.11133333311111333; float NewConvertedFloat = 0.0; ssortingng FirstSsortingng = " "; ssortingng SecondSsortingng = " "; ssortingngstream ss (ssortingngstream::in | ssortingngstream::out); ss << MyFloat; FirstString = ss.str(); // Take out how ever many decimal places you want // (this is a string it includes the point) SecondString = FirstString.substr(0,5); //whatever precision decimal place you want // Convert it back to a float stringstream(SecondString) >> NewConvertedFloat; cout << NewConvertedFloat; system("pause"); 

It might be an inefficient dirty way of conversion but heck, it works lol. And it's good, because it applies to the actual float. Not just affecting the output visually.

J’ai fait ça:

 #include  using namespace std; double roundh(double number, int place){ /* place = decimal point. Putting in 0 will make it round to whole number. putting in 1 will round to the tenths digit. */ number *= 10^place; int istack = (int)floor(number); int out = number-istack; if (out < 0.5){ floor(number); number /= 10^place; return number; } if (out > 0.4) { ceil(number); number /= 10^place; return number; } }