我推荐@Jens Gustedt的十六进制解决方案:使用%a。
OP想要“以最大精度打印(或至少打印到最重要的小数位)”。
一个简单的例子是如何打印1/7:
#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01
但是让我们深入了解一下...
从数学上讲,答案是“0.142857 142857 142857 ...”,但我们使用的是有限精度浮点数。假设我们使用IEEE 754双精度二进制。 因此,OneSeventh = 1.0 / 7.0
的结果如下所示。同时显示了前一个和后一个可表示的double
浮点数。
OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after = 0.1428571428571428 769682682968777953647077083587646484375
打印double
的精确十进制表示法有限的用途。
C有两组宏在<float.h>
中可以帮助我们。
第一组是在十进制字符串中打印有效数字的数量,以便在扫描字符串时获取原始浮点数。
它们显示了C规范的最小值和示例C11编译器。
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)
第二组是指一个字符串能够被扫描成一个浮点数并打印出来仍然保持相同的字符串呈现方式中的有效数字位数。这些数字与C语言的规范中的最小值以及C11编译器的示例一起显示。我相信在C99之前就已经可用了。
FLT_DIG 6, 6 (float)
DBL_DIG 10, 15 (double)
LDBL_DIG 10, 18 (long double)
第一组宏似乎符合楼主的要求,能保留有效数字。但是那个宏并不总是可用。
"+ 3"是我之前回答的关键。问题在于,如果已知往返转换字符串-FP-字符串(C89后可用的第2组宏),如何确定FP-字符串-FP的数字?通常,结果是加3。
现在已知要打印多少个有效数字,并由<float.h>
控制。
要打印N个有效十进制数字,可以使用各种格式。
使用"%e"
,精度字段是小数点后面的位数。因此,应该用-1
。注意:这个-1
不在最初的int Digs = DECIMAL_DIG;
中。
printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01
使用"%f"
格式说明符时,precision字段表示小数点后的位数。
例如,对于像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是显示默认值,而不是数字的精度。
printf("%f", val)
,这种方法已经是可移植、高效和默认的。 - bobobobo