如何找出两个变量大致相等?

我正在编写unit testing来validation数据库中的计算,并且存在大量的舍入和截断以及有时候数字稍微偏离的东西。

在validation时,我发现很多时候事情会通过,但说它们失败了 – 例如,数字将是1,我得到0.999999

我的意思是,我可以把所有东西都变成一个整数但是因为我使用了很多随机样本,最终我会得到这样的东西

10.5 10.4999999999

一个将圆到10,另一个将圆到11。

在需要大致正确的地方时,我该如何解决这个问题呢?

定义容差值(也称为’epsilon’或’delta’),例如0.00001,然后用于比较差异,如下所示:

if (Math.Abs(a - b) < delta) { // Values are within specified tolerance of each other.... } 

你可以使用Double.Epsilon但你必须使用倍增因子。

更好的是,编写一个扩展方法来做同样的事情。 我们的unit testing中有类似Assert.AreSimiliar(a,b)东西。

Microsoft的Assert.AreEqual()方法有一个带有delta的重载: public static void AreEqual(double expected, double actual, double delta)

NUnit还为其Assert.AreEqual()方法提供了一个重载,允许提供增量。

您可以提供一个函数,其中包含两个值之间可接受差异的参数。 例如

 // close is good for horseshoes, hand grenades, nuclear weapons, and doubles static bool CloseEnoughForMe(double value1, double value2, double acceptableDifference) { return Math.Abs(value1 - value2) <= acceptableDifference; } 

然后打电话给它

 double value1 = 24.5; double value2 = 24.4999; bool equalValues = CloseEnoughForMe(value1, value2, 0.001); 

如果你想稍微专业一点,你可以调用函数ApproximatelyEquals或类似的东西。

 static bool ApproximatelyEquals(this double value1, double value2, double acceptableDifference) 

我没有检查添加了哪个MS测试版但在v10.0.0.0中Assert.AreEqual方法有重载接受delta参数并进行近似比较的重载。

即https://msdn.microsoft.com/en-us/library/ms243458(v=vs.140).aspx

 // // Summary: // Verifies that two specified doubles are equal, or within the specified accuracy // of each other. The assertion fails if they are not within the specified accuracy // of each other. // // Parameters: // expected: // The first double to compare. This is the double the unit test expects. // // actual: // The second double to compare. This is the double the unit test produced. // // delta: // The required accuracy. The assertion will fail only if expected is different // from actual by more than delta. // // Exceptions: // Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: // expected is different from actual by more than delta. public static void AreEqual(double expected, double actual, double delta); 

比较浮点数的一种方法是比较将它们分开的浮点表示的数量。 这个解决方案对数字的大小无动于衷,因此您不必担心其他答案中提到的“epsilon”的大小。

可以在这里找到算法的描述(最后是AlmostEqual2sComplement函数),这里是我的C#版本。

更新:提供的链接已过时。 这里包含一些改进和错误修正的新版本

 public static class DoubleComparerExtensions { public static bool AlmostEquals(this double left, double right, long representationTolerance) { long leftAsBits = left.ToBits2Complement(); long rightAsBits = right.ToBits2Complement(); long floatingPointRepresentationsDiff = Math.Abs(leftAsBits - rightAsBits); return (floatingPointRepresentationsDiff <= representationTolerance); } private static unsafe long ToBits2Complement(this double value) { double* valueAsDoublePtr = &value; long* valueAsLongPtr = (long*)valueAsDoublePtr; long valueAsLong = *valueAsLongPtr; return valueAsLong < 0 ? (long)(0x8000000000000000 - (ulong)valueAsLong) : valueAsLong; } } 

如果您想比较浮点数,请将所有double更改为float ,将long更改为int ,将0x8000000000000000更改为0x80000000

使用representationTolerance参数,您可以指定容错的大小。 值越高意味着接受越大的错误。 我通常使用值10作为默认值。

问题是询问如何在unit testing中断言某些内容几乎相同。 通过使用内置的Assert.AreEqual函数断言某些内容几乎相等。 例如:

Assert.AreEqual(expected: 3.5, actual : 3.4999999, delta:0.1);

这个测试将通过。 问题解决了,无需编写自己的function!