This cannot be done using standard printf format specifiers. The closest you could get would be:
printf("%.6g", 359.013); // 359.013 printf("%.6g", 359.01); // 359.01
but ".6" is the total numerical width, therefore
printf("%.6g", 3.01357);
breaks it.
What you can do is sprintf("%.20g") number in the string buffer, then manipulate the string to have only N characters after the decimal point.
Assuming your number is in the num variable, the following function removes everything except the first N decimal places, and then removes the trailing zeros (and the decimal point if they are all zeros).
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 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'; } } }
If you are not comfortable with the truncation aspect (which will turn 0.12399 to 0.123 , rather than 0.124 it to 0.124 ), you can actually use the rounding capabilities already provided by printf . You just need to parse the number first to dynamically create the width, then use them to turn the number into a string:
#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; }
The whole point of nDecimals() in this case is to work out the field width correctly, and then format the number using a format string based on this. The test harness main() shows this in 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
Once you have a properly rounded value, you can pass it again to morphNumericString() to remove trailing zeros by simply changing:
nDecimals (str, num[i], 3);
at
nDecimals (str, num[i], 3); morphNumericString (str, 3);
(or calling morphNumericString at the end of nDecimals , but in this case I would probably just combine the two into one function), and you will get:
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