Code could use "%.18e"
or "%.18g"
, but the question is how large should "18" be? Is 18 the best value? The answer lies in DBL_DECIMAL_DIG
.
DBL_DECIMAL_DIG
is the minimum number of significant digits to print to insure the round-trip of double
to string to the same exact double
for all double
.
Recommend using format specifier "%.*e"
.
Note that the "18" in "%.18e"
is the number of significant digits after the decimal point. So "%.18e"
prints 19 significant digits.
Use printf("%a", x);
which prints in a hexadecimal output.
For a decimal output:
#include <float.h>
// sign + digit + dp + digits + e + sign + expo + \0
char buf[1 + 1 + 1 + (DBL_DECIMAL_DIG - 1) + 1 + 1 + 5 + 1];
sprintf(buf, "%.*e", DBL_DECIMAL_DIG - 1, x);
Ref Printf width specificer to maintain precision of floating-point value
A number like y = 1.0/3.0
using the typical double
binary64 format would need to see about 53 decimal digits to see its exact value. But many of the trailing digits are not needed for a successful round-trip.
Now we know the most digits to print, use the below to get rid of those pesky trailing 0
digits.
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
char *trim0(double x, char *buf) {
sprintf(buf, "% .*e", DBL_DECIMAL_DIG - 1, x);
if (isfinite(x)) {
char *p = &buf[DBL_DECIMAL_DIG + 1]; // address of last significand digit
char *t;
for (t=p; *t == '0'; t--);
memmove(t+1, p+1, strlen(p+1)+1);
}
return buf;
}
int main(void) {
char buf[1 + 1 + 1 + (DBL_DECIMAL_DIG - 1) + 1 + 1 + 5 + 1];
printf("%s\n", trim0(1.2, buf));
printf("%s\n", trim0(1.0/7, buf));
return 0;
}
Output
1.2e+00
1.4285714285714285e-01