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.
float
type offers. (Decimal values after the 6th will likely be further and further off). Look up the actual#define
d value ofFLT_DIG
on your platform, all bets say it will just be 6. – Mcpeakprintf( "%f", val );
which is already portable, efficient, and the default. – Mcpeakdouble
. As yourdouble
gets extremely large (very far from 1.0), it actually gets less accurate in the decimal portion (value portion less than 1.0). So you can't really have a satisfactory answer here, because your question has a false assumption in it (namely that allfloat
s/double
s are created equal) – Mcpeak%.12f
will just print 12 decimals, regardless if that accuracy is available from your variable type or not. You need to consider that the "printed" accuracy available (# characters printed) is completely arbitrary. The accuracy available in afloat
ordouble
is dependent on the number of mantissa bits used in the data type, as well as on the size of the number.printf
doesn't consider the size of the number however. So the answer to your question is no, you cannot print a number withprintf
to the "maximum precision possible" – Mcpeakfloat
. Forfloat
, I would recommend usingprintf("%.*e", OP_FLT_Digs-1, x)
where OP_FLT_Digs is derived correspondingly as OP_DBL_Digs below. IMHO, your focus isfloat-text-float
round tripping and that is exactly, by C spec, what xxx_DECIMAL_DIG provide. Of course%a
is great, but I assume you prefer decimal text. – Silda