C# 除法时精度损失加倍
本文关键字:损失 精度 除法 | 更新日期: 2023-09-27 18:33:14
我知道这已经被一次又一次地讨论过了,但我似乎甚至无法得到最简单的双精度数除法的例子,以在 C# 中产生预期的、不四舍五入的结果 - 所以我想知道是否有一些编译器标志或其他我没有想到的奇怪的东西。 请考虑以下示例:
double v1 = 0.7;
double v2 = 0.025;
double result = v1 / v2;
当我在最后一行之后中断并在 VS 调试器中检查它时,"result"的值为 27.99999999999996。 我知道我可以通过更改为"十进制"来解决它,但在周围程序的情况下这是不可能的。 像这样的两个低精度双精度不能除以正确的值 28 不是很奇怪吗? Math.Round的唯一解决方案真的是
像这样的两个低精度双精度不能除以正确的值 28 不是很奇怪吗?
不,不是真的。0.7 和 0.025 都不能在 double
类型中精确表示。涉及的确切值为:
0.6999999999999999555910790149937383830547332763671875
0.025000000000000001387778780781445675529539585113525390625
现在你对这个部门没有给出正好 28 个感到惊讶吗?垃圾进,垃圾出...
正如您所说,准确表示十进制数的正确结果是使用 decimal
.如果程序的其余部分使用了错误的类型,那只是意味着您需要找出哪个更高:获得错误答案的成本,还是更改整个程序的成本。
精度始终是一个问题,以防您处理float
或double
。
这是计算机科学中的一个已知问题,每种编程语言都受到它的影响。为了尽量减少这些主要与舍入有关的误差,一个完整的数值分析领域专门用于它。
例如,让我们采用以下代码。
你会期待什么?
你会期望答案是1
,但事实并非如此,你会得到0.9999907
.
float v = .001f;
float sum = 0;
for (int i = 0; i < 1000; i++ )
{
sum += v;
}
<</div>
div class="answers"> 这与double
数字的"简单"或"小"无关。严格来说,0.7
或0.025
都不能准确地存储在计算机内存中,因此,如果您追求高精度,对它们执行计算可能会提供有趣的结果。
所以是的,使用decimal
或圆形。
用类比来解释这一点:
想象一下,您正在以 3 为基地工作。在基数 3 中,0.1 是(十进制)1/3,即 0.333333333'。
因此,您可以在以 3 为底准确表示 1/3(十进制),但在尝试以十进制表示时会出现舍入错误。
好吧,你可以用一些十进制数得到完全相同的东西:它们可以完全用十进制表示,但它们不能用二进制精确表示;因此,你会得到它们的舍入误差。
对第一个问题的简短回答:不,这并不奇怪。浮点数是实数的离散近似值,这意味着当您进行算术运算时,舍入误差将传播和缩放。
有一个完整的数学领域称为数值分析,它基本上处理如何在处理此类近似时最小化错误。
通常的浮点不精确性。并非每个数字都可以表示为双精度,这些微小的表示不准确加起来。这也是您不应该将双精度与确切数字进行比较的原因。我刚刚测试了它,result.ToString()
显示了28
(也许double.ToString()
发生了某种四舍五入? 不过result == 28
false
回来了。(int)result
27
回来了.所以你只需要期待这样的不精确性。