Esto no se puede hacer con los printfespecificadores de formato normales . Lo más cercano que podría obtener sería:
printf("%.6g", 359.013); // 359.013
printf("%.6g", 359.01); // 359.01
pero ".6" es el ancho numérico total, por lo que
printf("%.6g", 3.01357); // 3.01357
lo rompe.
Lo que puede hacer es colocar sprintf("%.20g")el número en un búfer de cadena y luego manipular la cadena para que solo tenga N caracteres más allá del punto decimal.
Suponiendo que su número está en la variable num, la siguiente función eliminará todos los Ndecimales menos los primeros , luego eliminará los ceros finales (y el punto decimal si fueran todos ceros).
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 no está satisfecho con el aspecto de truncamiento (que se convertiría 0.12399en en 0.123lugar de redondearlo 0.124), puede utilizar las funciones de redondeo que ya proporciona printf. Solo necesita analizar el número de antemano para crear dinámicamente los anchos, luego usarlos para convertir el número en una cadena:
#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;
}
En nDecimals()este caso, el objetivo es calcular correctamente los anchos de campo y luego formatear el número usando una cadena de formato basada en eso. El arnés de prueba main()muestra esto en acción:
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
Una vez que tenga el valor redondeado correctamente, puede volver a pasarlo morphNumericString()para eliminar los ceros finales simplemente cambiando:
nDecimals (str, num[i], 3);
dentro:
nDecimals (str, num[i], 3);
morphNumericString (str, 3);
(o llamando morphNumericStringal final de nDecimalspero, en ese caso, probablemente combinaría los dos en una función), y terminas con:
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