繁体   English   中英

划分双打时C#精度损失

[英]C# loss of precision when dividing doubles

我知道这已经一次又一次地讨论了,但是我似乎无法得到一个一步一步的双重划分的最简单的例子,导致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 如果你的程序的其余部分使用了错误的类型,那只意味着你需要解决更高的问题:获得错误答案的成本,或者更改整个程序的成本。

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

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

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

你会期待什么?

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

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

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

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

通过类比来解释这个:

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM