为什么0.9循环不总是等于1

6

数学上,可以证明0.9循环等于1。然而,这个问题并不涉及无穷大、收敛或其背后的数学原理。

在C#中,可以用以下方式表示上述假设:

var oneOverNine = 1d / 9d;
var resultTimesNine = oneOverNine * 9d;

使用上面的代码,(resultTimesNine == 1d) 的评估结果为true。
当使用小数时,评估结果为false,但我的问题并不是关于double和decimal的差异精度。
由于没有类型具有无限精度,因此double如何保持这样的相等性,而decimal却没有呢?关于上述代码中的oneOverNine变量在内存中的存储方式,文字之间发生了什么事情?

我假设进行四舍五入。对于双精度浮点数,向1.0方向舍入,对于单精度浮点数,则远离1.0方向舍入。 - millimoose
1
使用哪个版本的C#、编译器和操作系统?问这个问题是因为在64位Win7机器上使用VS2010,无论是x86还是x64,对于浮点数和双精度浮点数都会得到“true”。 - Joel Rondeau
@JoelRondeau 这是一个好问题,在我的当前机器上(VS2010,Win7 x64),我得到了与您相同的结果,但对于十进制数却是false,因此存在精度差异,但这对比较很有趣。 - Tom Bowers
在不同的机器上运行相同的代码得到不同的答案,这让我想起了 Lippert 的这个回答:https://dev59.com/SGoy5IYBdhLWcg3wD5_H#8795656 - Joel Rondeau
2个回答

11

这取决于用于获取最接近1/9可表示值的四舍五入方式,结果可能会有所不同。您可以在Rob Kennedy的有用网页上研究可表示性问题:http://pages.cs.wisc.edu/~rkennedy/exact-float

但不要认为double能够实现精确性。它不能。如果您尝试2/9、3/9等,就会发现四舍五入的情况会有所不同。归根结底,1/9在二进制浮点数中无法准确表示。因此会发生舍入并且计算受到舍入误差的影响。


2
上面代码中“行与行之间”文字上发生了什么,关于oneOverNine变量在内存中的存储方式?
你所询问的是IEEE 754。这是C#、它的底层.Net运行时和大多数其他编程平台用来存储和操作十进制值的规范。这是因为对IEEE 754的支持通常直接在CPU/芯片组级别实现,使其比仅在软件中实现的替代方案更加高效,并且在构建编译器时更容易,因为操作几乎会直接映射到特定的CPU指令。

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