A brute force method tries various precisions of %.*g
until success.
The major obstacle to calculating the width of the print out before calling printf()
is that corner cases exist like 0.9995. The subtle effects of rounding make it that it is simpler to call sprintf()
a subsequent time. Additional code could be uses to make a better initial guess rather than starting at prec = n - 1
int g_print(double x, int n) {
int width;
char buffer[n + 1];
for (int prec = n - 1; prec >= 0; prec--) {
width = snprintf(buffer, sizeof buffer, "%.*g", prec, x);
// printf(" n:%2d p:%2d w:%2d <%s>\n", n, prec, width, buffer);
if (width > 0 && (unsigned) width < sizeof buffer) {
return printf("%2d <%s>\n", n, buffer);
}
}
// Try with %f
width = snprintf(buffer, sizeof buffer, "%.0f", x);
if (width > 0 && (unsigned) width < sizeof buffer) {
return printf("%2d <%s>\n", n, buffer);
}
printf("%2d Fail %e\n", n, x);
return 0; // fail
}
void g_print_test(double x) {
// Need at least width 7 for all values
for (int n = 8; n >= 1; n--) {
if (g_print(x, n) == 0)
break;
}
}
int main() {
g_print_test(1.2345678);
g_print_test(0.1234567);
g_print_test(123.45678);
g_print_test(DBL_MAX);
g_print_test(-DBL_MAX);
g_print_test(-DBL_MIN);
return 0;
}
Output
n text...
8 <1.234568>
7 <1.23457>
6 <1.2346>
5 <1.235>
4 <1.23>
3 <1.2>
2 <1>
1 <1>
8 <0.123457>
7 <0.12346>
6 <0.1235>
5 <0.123>
4 <0.12>
3 <0.1>
2 <0>
1 <0>
8 <123.4568>
7 <123.457>
6 <123.46>
5 <123.5>
4 <123>
3 <123>
2 Fail 1.234568e+02
8 <1.8e+308>
7 <2e+308>
6 <2e+308>
5 Fail 1.797693e+308
8 <-2e+308>
7 <-2e+308>
6 Fail -1.797693e+308
8 <-2e-308>
7 <-2e-308>
6 <-0>
5 <-0>
4 <-0>
3 <-0>
2 <-0>
1 Fail -2.225074e-308