我知道这已经再次讨论时间和时间,但我似乎无法得到甚至双打的一步师的最简单的例子,导致C#的预期,未经四舍五入的结果 - 所以我想,如果可能还有一些就是编译器标记或别的怪我没有想到的。 考虑下面这个例子:
double v1 = 0.7;
double v2 = 0.025;
double result = v1 / v2;
当我最后一行后断裂,在VS调试器检查它,“结果”的值是27.999999999999996。 我知道,我可以通过改变解决它“小数”,但不可能在周围程序的情况下。 这难道不奇怪的是,两个低精度双打这样不能分割到的28正确的价值? 是唯一的解决方案真正Math.Round结果呢?
这难道不奇怪的是,两个低精度双打这样不能分割到的28正确的价值?
不,不是真的。 既不0.7 0.025也不可以在精确表示double
型。 涉及的精确值:
0.6999999999999999555910790149937383830547332763671875
0.025000000000000001387778780781445675529539585113525390625
现在,你感到惊讶的是,分工不给确切28? 垃圾进垃圾出...
正如你所说的,代表十进制数字正确的结果究竟是使用decimal
。 如果你的程序的其余部分使用了错误的类型,只是意味着你需要找出哪些是更高:得到错误的答案的费用,或改变整个计划的成本。
它没有任何关系如何“简单”或“小”的double
数字。 严格地说,无论是0.7
或0.025
可以存储在计算机的内存究竟这些数字,所以执行,如果你是沉重的精度后,对他们的计算可以提供有趣的结果。
所以,是的,使用decimal
或圆形。
要通过类比解释:
假设正在基座3工作在基体3,是0.1(十进制)1/3,或0.333333333' 。
所以,你可以完全代表在基地3 1/3(十进制),但你要表达的是十进制时,舍入误差。
好了,就可以得到同样的事情与一些十进制数字:他们可以用十进制明确地表达,但也不能以二进制形式明确地表达; 因此,你会得到与他们的舍入误差。
精密始终是一个问题,如果你正在处理float
或double
。
它在计算机科学和每一个编程语言的一个已知的问题是受到它的影响。 为了尽量减少这些类型的错误,这大多与舍入的,完整场数值分析是献给它。
例如,我们采取如下的代码。
你会得到什么?
你会想到的答案是1
,但这种情况并非如此,你会得到0.9999907
。
float v = .001f;
float sum = 0;
for (int i = 0; i < 1000; i++ )
{
sum += v;
}
简短的回答你的第一个问题:不,这不奇怪。 浮点数是实数,这意味着舍入误差将传播和规模,当你做算术运算的离散近似。
即使世界的数学称为数字analyis,基本上解决了如何使用这种近似工作时,错误最小化的整个领域。
这是通常的浮点不精确。 不是每个数字可以表示为一个双,和那些较小的不准确性表示加起来。 这也是一个原因,你不应该双打比较确切的数字。 我只是测试它, result.ToString()
显示28
(也许某种四舍五入的发生在double.ToString()
result == 28
返回false
,但。 和(int)result
返回27
。 所以你只需要期待类似的不精确。