IEEE浮点数转换为精确的十进制字符字符串。

3
printf('%.9e', value)会打印出IEEE单精度浮点数(C/C++ float)的确切十进制表示吗?
同样地,如果value是IEEE双精度浮点数(C/C++ double),那么printf('%.17e', value)是否也如此呢?
如果不是,我该如何做到?
看起来printf('%.17f', value)printf('%.17g', value)均不会。

1
我认为每个二进制数都可以准确地表示为十进制数,所以我两者都认同。我知道并非每个十进制数都可以准确地表示为二进制数,但我不关心这一点。我假设该数字已经存在于浮点数或双精度浮点数中作为二进制数。我实际上不确定如何举例说明。 - Patrick
2
一个IEEE754单精度浮点数具有23位精度,而10只有一个二的幂因子,因此我认为可能会找到一个单精度浮点数,需要23个有效十进制数字才能准确表示。 - EOF
1
必读资料:计算机科学家应该了解的浮点数知识 - Thomas Matthews
1
@OliverCharlesworth:它解释了任何值的精确十进制表示是如何被解释的,强调精确 - Thomas Matthews
1
以数字1.0/3.0为例。打印9位小数比打印17位更准确吗? - Thomas Matthews
显示剩余18条评论
2个回答

3

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) 将打印出足够多的小数位,以便可以扫描它并获得相同的值 - (往返)。

从您对这个问题的回答中(https://dev59.com/-mQn5IYBdhLWcg3wa2qV),似乎`FLT_DIG`和`DBL_DIG`是用于从字符串转换为数字而不是从数字转换为字符串?我只使用9和17会安全吗?或者会因平台而异? - Patrick
直到现在我才意识到,精确的十进制字符串和需要保留原浮点数所有信息的十进制字符串是两回事。我只需要保留原浮点数所有信息的十进制字符串。 - Patrick
@Patrick 另一篇文章解释了需要什么。有趣的是,超过FLT_DECIMAL_DIG,DBL_DECIMAL_DIG位数可能会在某些情况下引起问题。明确地说,从基数A到基数B再回到基数A,与从基数B到基数A再回到基数B具有不同的要求。这就是DBL_DIGDBL_DECIMAL_DIG之间的区别。如果可能,请使用十六进制 - chux - Reinstate Monica
DECIMAL_DIG是否适用于单精度和双精度?例如,printf("%.*e", DECIMAL_DIG - 1, value) - Patrick
让我们在聊天中继续这个讨论。点击此处进入聊天室 - chux - Reinstate Monica
显示剩余13条评论

2

IEEE-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

我不担心从十进制到二进制的转换。我注意到在列表中,除了最后一个数字外,在小数点后面没有超过17个非零数字。 - Patrick
我认为混淆的地方在于,例如在单点情况下,给定一个浮点数及其无符号表示(最接近的9个小数位),仅通过改变1个无符号表示就只会改变浮点数的第6个小数位。(例如123.456(123.456001) 最接近的无符号表示是 1123477881。改变1个后,1123477882 会导致浮点数变化到 123.456008911 - David C. Rankin
@Patrick:“小数点后不超过17位非零数字?”是的,但请记住,每个数字在小数部分都只有1个比特设置。表格左侧的数字是该数字的十六进制表示。3f8代表指数为0,其余比特为小数部分。您可以在小数部分中使用任何比特组合。例如,0x3f820001将具有22个非零数字,您可以通过添加以0x3f820000和0x3f800001开头的两行来查看。结果为1.01562511920928955078125。 - user3386109
我猜我被这个陈述搞糊涂了:“如果将IEEE 754单精度转换为至少具有9个有效十进制数字的十进制字符串,然后再转换回单精度,则最终数字必须与原始数字匹配。” - Patrick
2
@Patrick 当你转换为十进制字符串时,你会四舍五入到最接近的具有9个有效数字的小数值。当转换回二进制时,你会四舍五入到最接近的具有23个有效位的二进制数。你引用的声明中的保证是,舍入误差不会导致与开始时不同的值。 - user3386109

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接