Questo non può essere fatto con i normali printfidentificatori di formato. Il più vicino che potresti ottenere sarebbe:
printf("%.6g", 359.013); // 359.013
printf("%.6g", 359.01); // 359.01
ma ".6" è la larghezza numerica totale così
printf("%.6g", 3.01357); // 3.01357
lo rompe.
Quello che puoi fare è inseriresprintf("%.20g") il numero in un buffer di stringa, quindi manipolare la stringa per avere solo N caratteri oltre il punto decimale.
Supponendo che il tuo numero sia nella variabile num, la seguente funzione rimuoverà tutti i Ndecimali tranne i primi , quindi rimuoverà gli zeri finali (e il punto decimale se fossero tutti zeri).
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';
}
}
}
Se non sei soddisfatto dell'aspetto del troncamento (che si trasformerebbe 0.12399in 0.123anziché arrotondarlo a 0.124), puoi effettivamente utilizzare le funzionalità di arrotondamento già fornite da printf. Devi solo analizzare il numero in anticipo per creare dinamicamente le larghezze, quindi usarle per trasformare il numero in una stringa:
#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;
}
Il punto centrale nDecimals()in questo caso è calcolare correttamente le larghezze del campo, quindi formattare il numero utilizzando una stringa di formato basata su quella. Il test harness main()mostra questo in azione:
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 volta ottenuto il valore arrotondato correttamente, puoi passarlo di nuovo a morphNumericString()per rimuovere gli zeri finali semplicemente cambiando:
nDecimals (str, num[i], 3);
in:
nDecimals (str, num[i], 3);
morphNumericString (str, 3);
(o chiamando morphNumericStringalla fine di nDecimalsma, in tal caso, probabilmente combinerei semplicemente i due in una funzione), e finisci 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