1

我在这里有一个简单的示例应用程序,我将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在两种情况下都是如此。我该怎么做?

4

7 回答 7

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;
}

还请务必阅读这篇博文

于 2013-08-06T13:17:31.087 回答
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
于 2013-08-06T13:22:07.150 回答
0

浮点数在内存中的表示方式是个问题。

您应该阅读本文以更好地了解正在发生的事情:每个计算机科学家都应该知道的关于浮点运算的知识

于 2013-08-06T13:16:34.627 回答
0

有一整套思想反对使用Double.Epsilon和类似的数字......

我认为他们使用这个:(取自https://stackoverflow.com/a/2411661/613130 ,但通过nobugz的检查IsNaNIsInfinity建议进行了修改

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幻数”基于doubles 的精度略高于 15 位这一事实。

我会为你的数字添加它返回 true :-)

于 2013-08-06T13:26:09.237 回答
0

只需将四舍五入更改为 2 级,这将给出 TRUE

double result1 =Math.Round ( (1 * 2 * a) + (-1 * 1 * b),2);
于 2013-08-06T13:17:28.943 回答
0

使用 Math.Round() 会将 result1 舍入为正确的小数

result1 = Math.Round(result1, 1);
于 2013-08-06T13:18:40.430 回答
0

使用调试器,

result1=88.499999999999986;
expectedResult = 88.5

所以当使用 double 时,这些是不相等的。

于 2013-08-06T13:20:00.067 回答