printf('%.9e', value)
会打印出IEEE单精度浮点数(C/C++ float)的确切十进制表示吗?同样地,如果
value
是IEEE双精度浮点数(C/C++ double),那么printf('%.17e', value)
是否也如此呢?如果不是,我该如何做到?
看起来
printf('%.17f', value)
和printf('%.17g', value)
均不会。printf('%.9e', value)
会打印出IEEE单精度浮点数(C/C++ float)的确切十进制表示吗?value
是IEEE双精度浮点数(C/C++ double),那么printf('%.17e', value)
是否也如此呢?printf('%.17f', value)
和printf('%.17g', value)
均不会。printf('%.9e', value)是否总是打印出精确的十进制表示?
不是。考虑0.5,0.25,0.125,0.0625...每个值都是前一个值的一半,并且需要每个降幂次2的小数位数。
float
通常binary32可以表示约为pow(2,-127)
的值,而子规范甚至更小。它需要127+个小数位才能准确表示这些值。即使只计算有效数字,该数量也为89+。例如,一台机器上的FLT_MIN
是精确地
0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625
FLT_TRUE_MIN
,最小的非零次标准化值为151位数字:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
FLT_MAX
只有39位数字。
340282346638528859811704183484516925440
很少需要精确的十进制表示法来表示float
。将它们打印到FLT_DECIMAL_DIG
(通常为9)个有效数字就足以唯一地显示它们。许多系统不会打印超过几十个有效数字的精确十进制表示法。DBL_DIG
个有效数字(通常为15+)。大多数系统至少可以打印DBL_DECIMAL_DIG
(通常为17+)个有效数字。
Printf width specifier to maintain precision of floating-point value 涉及这些问题。
printf('%.*e', FLT_DECIMAL_DIG - 1, value)
将打印出足够多的小数位,以便可以扫描它并获得相同的值 - (往返)。FLT_DECIMAL_DIG,DBL_DECIMAL_DIG
位数可能会在某些情况下引起问题。明确地说,从基数A到基数B再回到基数A,与从基数B到基数A再回到基数B具有不同的要求。这就是DBL_DIG
和DBL_DECIMAL_DIG
之间的区别。如果可能,请使用十六进制。 - chux - Reinstate MonicaIEEE-754格式适用于32位浮点数,详见维基百科。
下表显示了每个比特的权重,假设指数为0,即1.0 <= N < 2.0
。表中最后一个数字是小于2.0的最大数字。
从表中可以看出,要得到32位浮点数的精确十进制数,需要至少打印小数点后23位。
3f800000 1.0000000000000000000000000 (1)
3fc00000 1.5000000000000000000000000 (1 + 2^-1)
3fa00000 1.2500000000000000000000000 (1 + 2^-2)
3f900000 1.1250000000000000000000000 (1 + 2^-3)
3f880000 1.0625000000000000000000000 (1 + 2^-4)
3f840000 1.0312500000000000000000000 (1 + 2^-5)
3f820000 1.0156250000000000000000000 (1 + 2^-6)
3f810000 1.0078125000000000000000000 (1 + 2^-7)
3f808000 1.0039062500000000000000000 (1 + 2^-8)
3f804000 1.0019531250000000000000000 (1 + 2^-9)
3f802000 1.0009765625000000000000000 (1 + 2^-10)
3f801000 1.0004882812500000000000000 (1 + 2^-11)
3f800800 1.0002441406250000000000000 (1 + 2^-12)
3f800400 1.0001220703125000000000000 (1 + 2^-13)
3f800200 1.0000610351562500000000000 (1 + 2^-14)
3f800100 1.0000305175781250000000000 (1 + 2^-15)
3f800080 1.0000152587890625000000000 (1 + 2^-16)
3f800040 1.0000076293945312500000000 (1 + 2^-17)
3f800020 1.0000038146972656250000000 (1 + 2^-18)
3f800010 1.0000019073486328125000000 (1 + 2^-19)
3f800008 1.0000009536743164062500000 (1 + 2^-20)
3f800004 1.0000004768371582031250000 (1 + 2^-21)
3f800002 1.0000002384185791015625000 (1 + 2^-22)
3f800001 1.0000001192092895507812500 (1 + 2^-23)
3fffffff 1.9999998807907104492187500
需要注意的一点是,在1和2之间只有2^23(大约800万)个浮点值。然而,在小数点后有23位数字的情况下,有10^23个数字,因此很少有小数可以精确地表示为浮点数。
举个简单的例子,数字1.1 没有 精确的表示方式。最接近1.1的两个32位浮点值是:
3f8ccccc 1.0999999046325683593750000
3f8ccccd 1.1000000238418579101562500
123.456
(123.456001
) 最接近的无符号表示是 1123477881
。改变1个后,1123477882
会导致浮点数变化到 123.456008911
) - David C. Rankin3f8
代表指数为0,其余比特为小数部分。您可以在小数部分中使用任何比特组合。例如,0x3f820001将具有22个非零数字,您可以通过添加以0x3f820000和0x3f800001开头的两行来查看。结果为1.01562511920928955078125。 - user3386109