我推荐@Jens Gustedt十六进制解决方案:使用%a.
OP希望"以最大精度打印(或至少打印到最有效的小数点)".
一个简单的示例是打印七分之一,如下所示:
#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01
但让我们更深入地挖洞...
从数学上讲,答案是"142857 142857 142857……",但是我们使用的是有限精度的浮点数.
我们假设是IEEE 754 double-precision binary.
所以OneSeventh = 1.0/7.0
的结果是下面的值.还示出了前面和后面的可表示的double
个浮点数.
OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after = 0.1428571428571428 769682682968777953647077083587646484375
打印double
的exact十进制表示法用途有限.
C在<float.h>
个宏中有2个宏家族可以帮助我们
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)
第二组是significant位数,字符串可以扫描成浮点,然后打印FP,仍然保留相同的字符串表示形式.图中显示了C规范的minimum值和一个sample C11编译器.我相信C99之前就有了.
FLT_DIG 6, 6 (float)
DBL_DIG 10, 15 (double)
LDBL_DIG 10, 18 (long double)
第一组宏似乎达到了OP的significant位数目标.但macro并不总是可用.
#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
"+3"是我先前答覆的症结所在.
它的中心是如果知道往返转换字符串-fp-string(设置#2宏可用C89),如何确定fp-string-fp的位数(设置#1宏可用后C89)?一般来说,结果是加3.
现在知道要打印的significant位数是多少,并通过<float.h>
驱动.
要打印N个significant位十进制数字,可以使用各种格式.
对于"%e"
,precision字段是指after位数,即前导位数和小数点.
printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01
对于"%f"
,precision字段是小数点after的位数.
对于像OneSeventh/1000000.0
这样的数字,需要OP_DBL_Digs + 6
才能看到所有的significant位数字.
printf("%.*f\n", OP_DBL_Digs , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285
注:许多是使用到"%f"
.它在小数点后显示6位;6是显示默认值,而不是数字的精度.