我在这里有一个简单的示例应用程序,我将乘法并添加double
变量,然后将它们与预期结果进行比较。在这两种情况下,结果都等于预期结果,但是当我进行比较时,它失败了。
static void Main(string[] args)
{
double a = 98.1;
double b = 107.7;
double c = 92.5;
double d = 96.5;
double expectedResult = 88.5;
double result1 = (1*2*a) + (-1*1*b);
double result2 = (1*2*c) + (-1*1*d);
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", a, b, result1, expectedResult == result1));
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", c, d, result2, expectedResult == result2));
Console.Read();
}
这是输出:
2x98.1 - 107.7 = 88.5
Equal to 88.5? False
2x92.5 - 96.5 = 88.5
Equal to 88.5? True
我需要能够在两种情况下捕获它实际上是True
。我该怎么做?
答案 0 :(得分:4)
浮点数通常不包含数学告诉我们的确切值,因为它们存储数字的方式。
要进行可靠的比较,您需要考虑一些差异:
private const double DoubleEpsilon = 2.22044604925031E-16;
/// <summary>Determines whether <paramref name="value1"/> is very close to <paramref name="value2"/>.</summary>
/// <param name="value1">The value1.</param>
/// <param name="value2">The value2.</param>
/// <returns><c>true</c> if <paramref name="value1"/> is very close to value2; otherwise, <c>false</c>.</returns>
public static bool IsVeryCloseTo(this double value1, double value2)
{
if (value1 == value2)
return true;
var tolerance = (Math.Abs(value1) + Math.Abs(value2)) * DoubleEpsilon;
var difference = value1 - value2;
return -tolerance < difference && tolerance > difference;
}
另请务必阅读this blog post。
答案 1 :(得分:1)
如果您需要更高的精确度(用于赚钱等),请使用decimal
。
var a = 98.1M;
var b = 107.7M;
var c = 92.5M;
var d = 96.5M;
var expectedResult = 88.5M;
var result1 = (2 * a) + (-1 * b);
var result2 = (2 * c) + (-1 * d);
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", a, b, result1, expectedResult == result1));
Console.WriteLine(String.Format("2x{0} - {1} = {2}\nEqual to 88.5? {3}\n", c, d, result2, expectedResult == result2));
输出:
2x98.1 - 107.7 = 88.5
Equal to 88.5? True
2x92.5 - 96.5 = 88.5
Equal to 88.5? True
答案 2 :(得分:0)
浮点数在内存中的表示方式存在问题。
您应该阅读本文以更好地了解最新情况:What Every Computer Scientist Should Know About Floating-Point Arithmetic
答案 3 :(得分:0)
只需将您的舍入更改为2级,这将为TRUE
double result1 =Math.Round ( (1 * 2 * a) + (-1 * 1 * b),2);
答案 4 :(得分:0)
使用Math.Round()将result1舍入为正确的小数
result1 = Math.Round(result1, 1);
答案 5 :(得分:0)
使用调试器,
result1=88.499999999999986;
expectedResult = 88.5
所以当使用double时,这些并不相等。
答案 6 :(得分:0)
有一整套思想反对使用Double.Epsilon
和类似的数字......
我认为他们使用了这个:(取自https://stackoverflow.com/a/2411661/613130,但通过nobugz的IsNaN
和IsInfinity
建议here进行了修改
public static bool AboutEqual(double x, double y)
{
if (double.IsNaN(x)) return double.IsNaN(y);
if (double.IsInfinity(x)) return double.IsInfinity(y) && Math.Sign(x) == Math.Sign(y);
double epsilon = Math.Max(Math.Abs(x), Math.Abs(y)) * 1E-15;
return Math.Abs(x - y) <= epsilon;
}
1E-15
“幻数”基于double
s精度略高于15位的事实。
我会为你的数字加上它返回true: - )