# Printf width specifier to maintain precision of floating-point value

I recommend @Jens Gustedt hexadecimal solution: use %a.

OP wants “print with maximum precision (or at least to the most significant decimal)”.

A simple example would be to print one seventh as in:

``````#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01
``````

But let’s dig deeper …

Mathematically, the answer is “0.142857 142857 142857 …”, but we are using finite precision floating point numbers.
Let’s assume IEEE 754 double-precision binary.
So the `OneSeventh = 1.0/7.0` results in the value below. Also shown are the preceding and following representable `double` floating point numbers.

``````OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh        = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after  = 0.1428571428571428 769682682968777953647077083587646484375
``````

Printing the exact decimal representation of a `double` has limited uses.

C has 2 families of macros in `<float.h>` to help us.
The first set is the number of significant digits to print in a string in decimal so when scanning the string back,
we get the original floating point. There are shown with the C spec’s minimum value and a sample C11 compiler.

``````FLT_DECIMAL_DIG   6,  9 (float)                           (C11)
DBL_DECIMAL_DIG  10, 17 (double)                          (C11)
LDBL_DECIMAL_DIG 10, 21 (long double)                     (C11)
DECIMAL_DIG      10, 21 (widest supported floating type)  (C99)
``````

The second set is the number of significant digits a string may be scanned into a floating point and then the FP printed, still retaining the same string presentation. There are shown with the C spec’s minimum value and a sample C11 compiler. I believe available pre-C99.

``````FLT_DIG   6, 6 (float)
DBL_DIG  10, 15 (double)
LDBL_DIG 10, 18 (long double)
``````

The first set of macros seems to meet OP’s goal of significant digits. But that macro is not always available.

``````#ifdef DBL_DECIMAL_DIG
#define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else
#ifdef DECIMAL_DIG
#define OP_DBL_Digs (DECIMAL_DIG)
#else
#define OP_DBL_Digs (DBL_DIG + 3)
#endif
#endif
``````

The “+ 3” was the crux of my previous answer.
Its centered on if knowing the round-trip conversion string-FP-string (set #2 macros available C89), how would one determine the digits for FP-string-FP (set #1 macros available post C89)? In general, add 3 was the result.

Now how many significant digits to print is known and driven via `<float.h>`.

To print N significant decimal digits one may use various formats.

With `"%e"`, the precision field is the number of digits after the lead digit and decimal point.
So `- 1` is in order. Note: This `-1` is not in the initial `int Digs = DECIMAL_DIG;`

``````printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01
``````

With `"%f"`, the precision field is the number of digits after the decimal point.
For a number like `OneSeventh/1000000.0`, one would need `OP_DBL_Digs + 6` to see all the significant digits.

``````printf("%.*f\n", OP_DBL_Digs    , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285
``````

Note: Many are use to `"%f"`. That displays 6 digits after the decimal point; 6 is the display default, not the precision of the number.

Categories c