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.8m
为true
。 您应该注意, decimal
使用浮点数,就像float
和double
float
数一样,除了基数为10而不是2.因为处理基数2非常容易和高度优化, decimal
要慢得多。 它也有自己的不准确性,只有在处理可用短数字(如0.7
和0.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是不可能的。
因此,无论何时使用双打,都要注意一些舍入错误。
因此,只要需要确切的数字,就不会使用双打,就像货币金额一样。