为什么Visual Studio 2008告诉我.9 - .8999999999999995 = 0.00000000000000055511151231257827?

8
当我在Visual Studio 2008的立即窗口中输入以下内容时:
? .9 - .8999999999999995
它会给我这个答案:
0.00000000000000055511151231257827
文档说double有15-16位精度,但它给了我一个具有32位精度的结果。那么所有额外的精度是从哪里来的呢?

29
我想知道在 Stack Overflow 上有多少与浮点数精度问题相关的问题。 - Mehrdad Afshari
5
太多了。这是一个非常简单的事情:十进制不等于二进制。然而,每个人都觉得有必要把它当作最惊人的事情来对待! - S.Lott
5
各位,请仔细阅读,这是关于为什么答案使用32位数字的问题,而不是关于不准确的问题。 - H H
2
Henk,我认为这个问题可以表述得更好一些。如果OP在问题的开头甚至提到他/她知道FP精度,那么可能就会停止所有FP答案了。 - Jim Deville
5
@Mehrdad:我写了一个脚本来计算,发现有201.00000001918371个这样的问题。不过我不确定我是如何计算出一个分数问题的,也许我会发布一个带有源代码的问题来寻求解释。 - toasteroven
显示剩余2条评论
6个回答

41

答案只有15-16个数字,前导零不计入。这个数字实际上更像是5.5511151231257827×10-16。尾数部分有15-16位数字。指数(-16)将小数点向左移动16位,但并不改变整个数字的位数。

编辑

得到一些评论后,我现在对真正发生的事情很好奇。我将所讨论的数字插入到了这个IEEE-754转换器中。它将最后的“27”四舍五入为“30”,但我认为这并没有改变结果。

转换器将数字分解为三个二进制部分:

符号:0(正数)
指数:-51
尾数:1.0100000000000000000000000000000000000000000000000000(二进制表示1.2510

因此,这个数字是1.012 × 2-51,或者1.2510 × 2-51。由于只存储了三个有效的二进制数字,这表明Lars可能说对了什么。它们不能是“随机噪声”,因为它们每次转换数字时都是相同的。

数据表明,唯一存储的数字是“5”。前导零来自指数,其余看似随机的数字来自计算2-51


那些其他数字都存储在哪里? - Barry Brown
不,这是二进制小数的十进制表示,包括其舍入误差。 - Dykam
3
“前导零不计入”是错误的。答案中重要的15-16位数字是0.0000000000000005。之后的数字是不正确的,仅因前导零将舍入误差转化为尾数而存在。正如Barry在他的编辑中所写的那样,结果被存储为1.252^(-51)=5.55110^(-16),这是一个只有1个小数位计算精度但有15-16位存储精度的数字。 - Lars D
使用Convert.ToSingle("9111111.4999999990")convert.ToSingle("9111111.4999999991")将出现更有趣的行为。这两个值都比9111112更接近于9111111,但后者会四舍五入。 - supercat

17

9
SO无法为每一个浮点数问题自动提供这个答案,这真是可惜。至少90%的浮点数问题都可以用这个答案回答正确。 - Richard
2
这并未解答他所提出的关于精度的问题。 - Ape-inago
5
不回答问题。问题是关于双精度浮点数的32位数字(不是16位)的。 - H H
+1 数字的位数并不是真正相关的部分,而是这个答案所解决的存储方法。 - StackOverflowed

14

在浮点数中,前导零并不影响精度(就浮点数而言--数学上,它们是有意义的)。前导零是由浮点数内部表示的指数部分引起的。

数字段55511151231257827(也称为尾数或有效数字)有17位十进制数字,这足以接近15-16位数字。

@Lars D: 你认为正确的东西,只有在问题的背景下才是正确的。 .9 - .8999999999999995 得到的浮点数的有效数字为0.625,指数为-50。将0.625 * 2-50得到5.5511151231257827e-16。现在,在原问题的背景之外,我们有一个具有17个有效数字的数字,这恰好是0.0000000000000005的最佳二进制逼近值。然而,对于浮点数的表示来说,那些前导零仍然不重要。


2
我downvote了这个答案,因为我认为你的回答是不正确的。在实际的减法运算中,15-16位精度只给出了0.0000000000000005,其余数字都是随机舍入误差。因此,在55511151231257827部分,只有1个正确的数字,其余数字都是舍入误差,由于前导零而被提升到尾数中。基本上,这32位数字是从减法中得出的16个有效数字,加上之后尾数中的16个噪声数字。这些零只有在结果存储后才变得不重要。 - Lars D
1
如果我再学化学的话,前导零将是有效数字。然而,计算机无法判断这些零是否应该是有效数字,这就是为什么答案中有大约16个非零数字的原因。 - Mark Rushakoff

4

? .9 - .8999999999999995

这个减法过程,使用15-16位有效数字,得到结果:

0.0000000000000005

其余的数字只是舍入误差。然而,由于计算机总是在第一个非零数字后存储15-16位有效数字,所以会显示舍入误差,并产生很多尾随的随机数字。因此,结果有来自减法操作的16位有效数字加上来自结果存储的16位数字,共32位。


3
“浮点”中的“浮动”意味着您得到了更接近5.5511151231257827 * 10^(-16)的东西。由于当然是在二进制下完成所有操作,所以它的表示方式并不完全一样,但关键是,该数字由有效数字和一个表示如何移动基数(小数点)的数字组成。像往常一样,维基百科可以为您提供更多详细信息: (第二个链接更专注于您特定的情况。)

0

我认为这是因为在二进制系统中,5是周期性的,因为它不能被2整除。然后Mark Rushakoff所说的就适用了。


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