241 votes

Arrondir un nombre à deux décimales en C

Comment arrondir un flottant (tel que 37,777779) à deux décimales (37,78) en C ?

15 votes

Vous ne pouvez pas arrondir correctement le nombre lui-même, car float (et double ) ne sont pas à virgule flottante décimale - ils sont à virgule flottante binaire - donc arrondir à des positions décimales n'a aucun sens. Vous pouvez toutefois arrondir la sortie.

70 votes

Ce n'est pas sans signification, c'est inexact. Il y a une grande différence.

2 votes

Quel type d'arrondi attendez-vous ? La moitié supérieure ou l'arrondi au pair le plus proche ?

452voto

Dale Hagglund Points 7159

Si vous souhaitez simplement arrondir le nombre à des fins d'édition, alors la fonction "%.2f" La chaîne de format est en effet la bonne réponse. Cependant, si vous souhaitez arrondir la valeur en virgule flottante pour un calcul ultérieur, quelque chose comme ce qui suit fonctionne :

#include <math.h>

float val = 37.777779;

float rounded_down = floorf(val * 100) / 100;   /* Result: 37.77 */
float nearest = roundf(val * 100) / 100;  /* Result: 37.78 */
float rounded_up = ceilf(val * 100) / 100;      /* Result: 37.78 */

Notez qu'il existe trois règles d'arrondi différentes que vous pouvez choisir : arrondi vers le bas (c'est-à-dire, tronquer après deux décimales), arrondi au plus proche, et arrondi vers le haut. En général, vous voulez arrondir au plus proche.

Comme plusieurs autres personnes l'ont souligné, en raison des bizarreries de la représentation en virgule flottante, ces valeurs arrondies ne seront peut-être pas exactement les valeurs décimales "évidentes", mais elles en seront très très proches.

Pour de plus amples informations sur les arrondis, et en particulier sur les règles de départage pour les arrondis les plus proches, voir l'article de Wikipédia sur les arrondis .

5 votes

Peut-il être modifié pour prendre en charge l'arrondi à une précision arbitraire ?

1 votes

Quand vous dites "précision arbitraire", vous parlez d'arrondir à, par exemple, trois au lieu de deux décimales, ou d'utiliser des bibliothèques qui implémentent des valeurs décimales de précision non bornée ? Si c'est le cas, faites ce que j'espère être des ajustements évidents à la constante 100 ; sinon, faites exactement les mêmes calculs que ci-dessus, mais avec la bibliothèque de précision multiple que vous utilisez.

2 votes

@DaleHagglung Le premier, merci. L'ajustement consiste-t-il à remplacer 100 par pow(10, (int)desiredPrecision) ?

103voto

Andrew Coleson Points 3159
printf("%.2f", 37.777779);

0 votes

Cette méthode est meilleure car il n'y a pas de perte de précision.

3 votes

@albert Cela présente également l'avantage de ne pas perdre de données. float comme val * 100 pourrait déborder.

43voto

therefromhere Points 21329

En supposant que vous parlez d'arrondir la valeur pour l'impression, alors Andrew Coleson y AraK sont correctes :

printf("%.2f", 37.777779);

Mais notez que si vous souhaitez arrondir le nombre à exactement 37,78 pour un usage interne (par exemple pour le comparer à une autre valeur), ce n'est pas une bonne idée, en raison de la façon dont les nombres à virgule flottante fonctionnent : vous ne voulez généralement pas faire de comparaisons d'égalité pour les nombres à virgule flottante, mais plutôt utiliser une valeur cible +/- une valeur sigma. Vous pouvez aussi coder le nombre sous forme de chaîne de caractères avec une précision connue, et comparer cette chaîne.

Voir le lien dans Réponse de Greg Hewgill à une question connexe qui explique également pourquoi vous ne devriez pas utiliser la virgule flottante pour les calculs financiers.

1 votes

Approuvé pour avoir abordé ce qui pourrait être la question derrière la question (ou la question qui aurait dû être derrière la question !). C'est un point assez important.

0 votes

En fait, 37,78 peut être présenté exactement par la virgule flottante. Les flottants ont 11 à 12 chiffres pour la précision. Cela devrait être suffisant pour adresser 3778 377.8 ou tout autre type de chiffre décimal à 4 chiffres.

0 votes

@HaryantoCiu Oui, c'est juste, j'ai modifié un peu ma réponse.

24voto

Daniil Points 733

Que dites-vous de ça ?

float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);

5 votes

-1 : a) cela ne fonctionnera pas pour les nombres négatifs (ok, l'exemple est positif mais quand même). b) vous ne mentionnez pas qu'il est impossible de stocker la valeur décimale exacte dans le float.

34 votes

@therefromhere : (a) Tu as raison (b) Qu'est-ce que c'est ? Un test de lycée ?

0 votes

:D @Danil belle réponse :)

20voto

AraK Points 38702
printf("%.2f", 37.777779);

Si vous voulez écrire en C-string :

char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);

0 votes

@Sinan : Pourquoi le montage ? @AraK : Non, vous devrait s'occuper de la taille :). Utilisez snprintf().

1 votes

@aib : Je suppose que c'est parce que /**/ sont des commentaires de style C et que la question est balisée pour C.

5 votes

C89 ne permettait que le style /**/, C99 a introduit le support du style //. Utilisez un compilateur boiteux/ancien (ou forcez le mode C89) et vous serez incapable d'utiliser le style //. Cela dit, nous sommes en 2009, considérons qu'il s'agit de styles C et C++.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X