划分双打时C#精度损失

我知道这已经一次又一次地讨论了,但我似乎无法得到一个一步一步的双重划分的最简单的例子,导致C#的预期的,不完整的结果 – 所以我想知道是否也许有一些编译器标志或其他奇怪的我没有想到的。 考虑这个例子:

double v1 = 0.7; double v2 = 0.025; double result = v1 / v2; 

当我在最后一行之后断开并在VS调试器中检查它时,“result”的值是27.999999999999996。 我知道我可以通过更改为“十进制”来解决它,但在周围程序的情况下这是不可能的。 像这样的两个低精度双倍不能分成28的正确值是不奇怪的? Math.Round的结果是唯一的解决方案吗?

像这样的两个低精度双倍不能分成28的正确值是不奇怪的?

不,不是真的。 在double类型中,0.7和0.025都不能精确表示。 涉及的确切值是:

 0.6999999999999999555910790149937383830547332763671875 0.025000000000000001387778780781445675529539585113525390625 

现在你觉得这个部门没有准确地给出28分吗? 垃圾进垃圾出…

如你所说,正确表示十进制数的正确结果是使用decimal 。 如果你的程序的其余部分使用了错误的类型,那只意味着你需要解决更高的问题:获得错误答案的成本,或者更改整个程序的成本。

它与double数字的“简单”或“小”无关。 严格来说, 0.70.025都不能存储为计算机内存中的那些数字,因此如果你精确度很高,那么对它们进行计算可能会提供有趣的结果。

所以是的,使用decimal或圆形。

通过类比来解释这个:

想象一下,你在基数3工作。在基数3中,0.1是(十进制)1/3,或0.333333333’。

因此,您可以在基数3中精确表示1/3(十进制),但在尝试以十进制表示时会出现舍入错误。

好吧,你可以用一些十进制数得到完全相同的东西:它们可以用十进制精确表示,但它们不能用二进制精确表示; 因此,你会得到它们的四舍五入错误。

如果你正在处理floatdouble ,精度总是一个问题。

它是计算机科学中的一个已知问题,每种编程语言都受其影响。 为了最大限度地减少这些与舍入主要相关的错误,我们专门研究了一个完整的数值分析领域。

例如,让我们采取以下代码。

你会期待什么?

你会期望答案是1 ,但事实并非如此,你会得到0.9999907

  float v = .001f; float sum = 0; for (int i = 0; i < 1000; i++ ) { sum += v; } 

简短回答你的第一个问题:不,这并不奇怪。 浮点数是实数的离散近似值,这意味着当您进行算术运算时,舍入误差将传播和缩放。

Theres是一个称为数值分析的整个数学领域,它基本上处理了在使用这种近似时如何最小化误差。

这是通常的浮点不精确。 并非每个数字都可以表示为double,并且这些次要表示不准确性会加起来。 这也是你不应该将双打与精确数字进行比较的原因。 我只是测试了它, result.ToString() double.ToString()显示28 (也许某种舍入发生在double.ToString() ?)。 result == 28但是返回false 。 并且(int)result返回27 。 所以你只需要期待那样的不精确。