IEEE 浮点数到精确的 base10 字符串
IEEE floating-point number to exact base10 character string
如果 value
是 IEEE 单精度浮点数(C/C++ 浮点数),printf('%.9e', value)
是否总是打印 value
的精确 base10 表示?
如果 value
是一个 IEEE 双精度浮点数(C/C++ 双精度),printf('%.17e', value)
是否同样适用?
如果不行,怎么办?
看来 printf('%.17f', value)
和 printf('%.17g', value)
不会。
32 位浮点数的 IEEE-754 格式在 this Wikipedia article 中有解释。
下面的table给出了每个位的位权重,假设指数为0,意思是
1.0 <= N < 2.0
。 table中的最后一个数是小于2.0的最大数。
从table可以看出,要从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万)个浮点数。但是,有10^23个小数点后23位的数字,所以很很少有十进制数具有精确的浮点表示。
作为一个简单的例子,数字 1.1 没有 有一个精确的表示。最接近 1.1 的两个 32 位浮点值是
3f8ccccc 1.0999999046325683593750000
3f8ccccd 1.1000000238418579101562500
Will printf('%.9e', value) always print the exact base10 representation?
没有。考虑 0.5、0.25、0.125、0.0625 .... 每个值都是前面的二分之一,并且每个 2 的递减幂都需要另一个小数位。
float
,通常 binary32 可以表示大约 pow(2,-127)
的值,次法线甚至更小。准确表示这些数字需要 127 位以上的小数位。即使只计算 significant 位数,那么数字也是 89+。例如 FLT_MIN
在一台机器上 正好
0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625
FLT_TRUE_MIN
,最小非零次正规数为151位:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
相比之下,FLT_MAX
只需要39位。
340282346638528859811704183484516925440
很少需要精确 float
的十进制表示。将它们打印到 FLT_DECIMAL_DIG
(通常为 9)位有效数字足以唯一地显示它们。许多系统不打印超出几十位有效数字的精确十进制表示。
我使用过的绝大多数系统打印 float/double
至少 DBL_DIG
有效数字(通常为 15+)。大多数系统至少会这样做 DBL_DECIMAL_DIG
(通常为 17+)位有效数字。
Printf width specifier to maintain precision of floating-point value 进入这些问题。
printf('%.*e', FLT_DECIMAL_DIG - 1, value)
会将 float
打印到足够的小数位以将其扫描回来并获得相同的值 - (往返)。
如果 value
是 IEEE 单精度浮点数(C/C++ 浮点数),printf('%.9e', value)
是否总是打印 value
的精确 base10 表示?
如果 value
是一个 IEEE 双精度浮点数(C/C++ 双精度),printf('%.17e', value)
是否同样适用?
如果不行,怎么办?
看来 printf('%.17f', value)
和 printf('%.17g', value)
不会。
32 位浮点数的 IEEE-754 格式在 this Wikipedia article 中有解释。
下面的table给出了每个位的位权重,假设指数为0,意思是1.0 <= N < 2.0
。 table中的最后一个数是小于2.0的最大数。
从table可以看出,要从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万)个浮点数。但是,有10^23个小数点后23位的数字,所以很很少有十进制数具有精确的浮点表示。
作为一个简单的例子,数字 1.1 没有 有一个精确的表示。最接近 1.1 的两个 32 位浮点值是
3f8ccccc 1.0999999046325683593750000
3f8ccccd 1.1000000238418579101562500
Will printf('%.9e', value) always print the exact base10 representation?
没有。考虑 0.5、0.25、0.125、0.0625 .... 每个值都是前面的二分之一,并且每个 2 的递减幂都需要另一个小数位。
float
,通常 binary32 可以表示大约 pow(2,-127)
的值,次法线甚至更小。准确表示这些数字需要 127 位以上的小数位。即使只计算 significant 位数,那么数字也是 89+。例如 FLT_MIN
在一台机器上 正好
0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625
FLT_TRUE_MIN
,最小非零次正规数为151位:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
相比之下,FLT_MAX
只需要39位。
340282346638528859811704183484516925440
很少需要精确 float
的十进制表示。将它们打印到 FLT_DECIMAL_DIG
(通常为 9)位有效数字足以唯一地显示它们。许多系统不打印超出几十位有效数字的精确十进制表示。
我使用过的绝大多数系统打印 float/double
至少 DBL_DIG
有效数字(通常为 15+)。大多数系统至少会这样做 DBL_DECIMAL_DIG
(通常为 17+)位有效数字。
Printf width specifier to maintain precision of floating-point value 进入这些问题。
printf('%.*e', FLT_DECIMAL_DIG - 1, value)
会将 float
打印到足够的小数位以将其扫描回来并获得相同的值 - (往返)。