Cela ne peut pas être fait avec les printf
spécificateurs de format normaux . Le plus proche que vous pourriez obtenir serait:
printf("%.6g", 359.013); // 359.013
printf("%.6g", 359.01); // 359.01
mais le ".6" est la largeur numérique totale, donc
printf("%.6g", 3.01357); // 3.01357
le casse.
Ce que vous pouvez faire est de placer sprintf("%.20g")
le nombre dans un tampon de chaîne, puis de manipuler la chaîne pour n'avoir que N caractères après la virgule décimale.
En supposant que votre nombre se trouve dans la variable num, la fonction suivante supprimera toutes les N
décimales sauf les premières , puis supprimera les zéros de fin (et le point décimal s'ils étaient tous des zéros).
char str[50];
sprintf (str,"%.20g",num); // Make the number.
morphNumericString (str, 3);
: :
void morphNumericString (char *s, int n) {
char *p;
int count;
p = strchr (s,'.'); // Find decimal point, if any.
if (p != NULL) {
count = n; // Adjust for more or less decimals.
while (count >= 0) { // Maximum decimals allowed.
count--;
if (*p == '\0') // If there's less than desired.
break;
p++; // Next character.
}
*p-- = '\0'; // Truncate string.
while (*p == '0') // Remove trailing zeros.
*p-- = '\0';
if (*p == '.') { // If all decimals were zeros, remove ".".
*p = '\0';
}
}
}
Si vous n'êtes pas satisfait de l'aspect troncature (qui tournerait 0.12399
en au 0.123
lieu d'arrondir à 0.124
), vous pouvez réellement utiliser les installations déjà fournies par arrondissement printf
. Il vous suffit d'analyser le nombre au préalable pour créer dynamiquement les largeurs, puis de les utiliser pour transformer le nombre en chaîne:
#include <stdio.h>
void nDecimals (char *s, double d, int n) {
int sz; double d2;
// Allow for negative.
d2 = (d >= 0) ? d : -d;
sz = (d >= 0) ? 0 : 1;
// Add one for each whole digit (0.xx special case).
if (d2 < 1) sz++;
while (d2 >= 1) { d2 /= 10.0; sz++; }
// Adjust for decimal point and fractionals.
sz += 1 + n;
// Create format string then use it.
sprintf (s, "%*.*f", sz, n, d);
}
int main (void) {
char str[50];
double num[] = { 40, 359.01335, -359.00999,
359.01, 3.01357, 0.111111111, 1.1223344 };
for (int i = 0; i < sizeof(num)/sizeof(*num); i++) {
nDecimals (str, num[i], 3);
printf ("%30.20f -> %s\n", num[i], str);
}
return 0;
}
L'intérêt de nDecimals()
dans ce cas est de calculer correctement les largeurs de champ, puis de formater le nombre en utilisant une chaîne de format basée sur cela. Le harnais de test main()
montre cela en action:
40.00000000000000000000 -> 40.000
359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.010
359.00999999999999090505 -> 359.010
3.01357000000000008200 -> 3.014
0.11111111099999999852 -> 0.111
1.12233439999999995429 -> 1.122
Une fois que vous avez la valeur correctement arrondie, vous pouvez à nouveau la passer à morphNumericString()
pour supprimer les zéros de fin en modifiant simplement:
nDecimals (str, num[i], 3);
dans:
nDecimals (str, num[i], 3);
morphNumericString (str, 3);
(ou appeler morphNumericString
à la fin de nDecimals
mais, dans ce cas, je combinerais probablement les deux en une seule fonction), et vous vous retrouverez avec:
40.00000000000000000000 -> 40
359.01335000000000263753 -> 359.013
-359.00999000000001615263 -> -359.01
359.00999999999999090505 -> 359.01
3.01357000000000008200 -> 3.014
0.11111111099999999852 -> 0.111
1.12233439999999995429 -> 1.122