C#为简单的数学运算获得奇怪的结果

我注意到一些奇怪的行为,同时添加两个双打,有时它的工作正确,有时不是!

这是第一个例子:

double num1 = 0.1 + 0.7; //Guess the result? 

容易 – 0.8 !!! 或不?

看看奇怪的结果:

在此处输入图像描述

猜猜是什么,if语句在else块内,并打印num1 – 而不是,它不打印0.799999999999993,它打印0.8。

所以我向前迈了一步,尝试了这段代码:

 if (0.1 + 0.7 == 0.8) //Returns false ?? { Console.WriteLine("Correct"); } 

好的,很奇怪,但是现在我找到了正确的方法,它应该使用f(float)。 我记得double有很多空格,所以它可以包含更多的数字,也许这就是原因。

 float num2 = 0.1f + 0.7f; if (num2 == 0.8f) //Perfect - finally works !!! { Console.WriteLine("Correct"); } else { Console.WriteLine(num2); } 

但是现在,我试试这个 – 再次它返回错误,为什么?

 if (0.1f + 0.7f == 0.8f) //Returns false :( { Console.WriteLine("Correct"); } 

手表调试结果时:

在此处输入图像描述

谁能解释我这里有什么问题? 那些错误吗?

提前致谢。

浮点运算不精确。 你应该阅读文章科学家应该知道的关于浮点运算的文章 。 如果您希望计算在十进制意义上精确,则应使用decimal类型,其中0.1m + 0.7m == 0.8mtrue 。 您应该注意, decimal使用浮点数,就像floatdouble float数一样,除了基数为10而不是2.因为处理基数2非常容易和高度优化, decimal要慢得多。 它也有自己的不准确性,只有在处理可用短数字(如0.70.1 )表示的数字时才准确,这使得它对财务数据有利。

理解浮点数的另一篇有用的文章是维基百科的双精度浮点格式 。

调用Math.Round方法以确保两个值具有相同的精度。 以下示例修改前一个示例以使用此方法,以便两个小数值相等:

 using System; public class Example { public static void Main() { double value1 = .333333333333333; double value2 = 1.0/3; int precision = 7; value1 = Math.Round(value1, precision); value2 = Math.Round(value2, precision); Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2)); } } // The example displays the following output: // 0.3333333 = 0.3333333: True 

这是答案: http : //www.codeproject.com/Articles/383871/Demystify-Csharp-floating-point-equality-and-relat

浮动值仅为近似值。 要比较两个浮点值,您需要检查它们之间的差异。 差异不能大于float.Epsilon

用它来比较这些值:

 bool AlmostEqualDoubles(double nVal1, double nVal2, int nPrecision = 6) { nPrecision = Math.Max(Math.Min(16, nPrecision), 0); double nEpsilon = 1.0; for (int i = 0; i < nPrecision; i++) nEpsilon *= 0.1; return (nVal2 - nEpsilon) < nVal1 && nVal1 < (nVal2 + nEpsilon); } 

在内部,double存储在base-2中的位中。 所有整数都可以精确地表示在base-2中,但是当它涉及分数时,它就是另一个问题。

与我们在十进制系统中无法精确地表示1/3结果的方式相同,在二元系统中,您无法表示所有分数。 由于十进制是基数为10,因此很容易用十进制表示x / 10,但在base-2中,某些x是不可能的。

因此,无论何时使用双打,都要注意一些舍入错误。

因此,只要需要确切的数字,就不会使用双打,就像货币金额一样。