Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 根据给定的精度,而不是在某个固定公差范围内,评估两个双精度是否相等_C#_Nunit_Floating Point - Fatal编程技术网

C# 根据给定的精度,而不是在某个固定公差范围内,评估两个双精度是否相等

C# 根据给定的精度,而不是在某个固定公差范围内,评估两个双精度是否相等,c#,nunit,floating-point,C#,Nunit,Floating Point,我正在运行NUnit测试来评估一些已知的测试数据和计算结果。这些数字是浮点双精度的,所以我不希望它们完全相等,但我不确定如何在给定精度下将它们视为相等 Assert.Less(Math.Abs(firstValue - secondValue), firstValue / Math.Pow(10, precision)); 在NUnit中,我们可以与固定公差进行比较: double expected = 0.389842845321551d; double actual = 0.38984

我正在运行NUnit测试来评估一些已知的测试数据和计算结果。这些数字是浮点双精度的,所以我不希望它们完全相等,但我不确定如何在给定精度下将它们视为相等

Assert.Less(Math.Abs(firstValue - secondValue), firstValue / Math.Pow(10, precision));
在NUnit中,我们可以与固定公差进行比较:

double expected = 0.389842845321551d;
double actual   = 0.38984284532155145d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
这对零以下的数字很好,但是随着数字的增长,公差确实需要改变,所以我们总是关心相同的精度位数

Assert.Less(Math.Abs(firstValue - secondValue), firstValue / Math.Pow(10, precision));
具体而言,该测试失败:

double expected = 1.95346834136148d;
double actual   = 1.9534683413614817d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
当然,更大的数字不能容忍

double expected = 1632.4587642911599d;
double actual   = 1632.4587642911633d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));

计算两个浮点数在给定精度下相等的正确方法是什么?NUnit中是否有内置的方法来执行此操作?

如何将每个项目转换为字符串并比较字符串

string test1 = String.Format("{0:0.0##}", expected);
string test2 = String.Format("{0:0.0##}", actual);
Assert.AreEqual(test1, test2);

我不知道是否有一种内置的方法可以使用nunit实现,但我建议将每个浮点数乘以所需精度的10倍,将结果存储为long,并将两个long相互比较。
例如:

double expected = 1632.4587642911599d;
double actual   = 1632.4587642911633d;
//for a precision of 4
long lActual = (long) 10000 * actual;
long lExpected = (long) 10000 * expected;

if(lActual == lExpected) {  // Do comparison
   // Perform desired actions
}

这是一个快速的想法,但是把它们向下移动到零度以下怎么样?应该类似于
num/(10^ceil(log10(num))
。我不确定它的效果如何,但这是一个想法

1632.4587642911599 / (10^ceil(log10(1632.4587642911599))) = 0.16324587642911599

这就是我的初衷(Java代码,但应易于翻译,并附带一个测试套件,这是您真正需要的):

public static boolean nearlyEqual(浮点a、浮点b、浮点ε)
{
最终浮动absA=数学abs(a);
最终浮动absB=数学abs(b);
最终浮差=数学绝对值(a-b);
如果(a*b==0){//a或b或两者都为零
//相对误差在这里没有意义
返回差<(ε*ε);
}else{//使用相对错误
返回差/(absA+absB)
真正棘手的问题是,当要比较的数字之一为零时,该怎么办。最好的答案可能是这样的比较应该总是考虑比较的数字的域含义而不是试图成为通用的。
const double significantFigures = 10;
Assert.AreEqual(Actual / Expected, 1.0, 1.0 / Math.Pow(10, significantFigures));
从msdn:

默认情况下,双精度值包含15位小数精度,但内部最多保留17位

那么让我们假设15岁

因此,我们可以说,我们希望公差达到相同的程度

小数点后有多少精确数字?我们需要知道从小数点到最高有效位的距离,对吗?震级。我们可以用Log10得到这个

然后我们需要将1除以10^精度,得到一个我们想要的精度值

现在,您需要比我做更多的测试用例,但这似乎是可行的:

  double expected = 1632.4587642911599d;
  double actual = 1632.4587642911633d; // really comes from a data import

  // Log10(100) = 2, so to get the manitude we add 1.
  int magnitude = 1 + (expected == 0.0 ? -1 : Convert.ToInt32(Math.Floor(Math.Log10(expected))));
  int precision = 15 - magnitude ;

  double tolerance = 1.0 / Math.Pow(10, precision);

  Assert.That(actual, Is.EqualTo(expected).Within(tolerance));

已经很晚了,这里可能有个陷阱。我用你的三组测试数据对它进行了测试,每一组都通过了。将
精度
更改为
16-量级
导致测试失败。将其设置为
14-幅值
明显导致其通过,因为公差更大。

两个值之间的差值应小于任何一个值除以精度

Assert.Less(Math.Abs(firstValue - secondValue), firstValue / Math.Pow(10, precision));
开放式FSU

实际|>应(在误差范围内)为预期值


是一个不错的选项(将其更改为相对比较,其中x必须在y的10%以内)。您可能需要为0添加额外的处理,否则在这种情况下会得到精确的比较。

我考虑过这一点,并同意将其转换为字符串是可行的。但不像您所说的那样,您希望使用每个值可用的完整精度转换为字符串,然后以相同的长度截断它们。然而,我希望得到一个数学上合适的结果,一个不那么粗糙的结果。这个解决方案意味着
0.999999999999999
将是不相等的
1.00000000000000
-但这不是故意的,是吗?这看起来至少是一个好的开始。这个计算对精度有什么影响?是否存在精度损失?显然,我不关心两个可比较值的完全精度,但如果我们在这两个方面都失去了精度,那么比较可能会产生一些误报。这在数学上与使用公差相同,只是以不同的方式应用。当然,如果期望值为零或接近它,则必须编写特殊情况代码。零有多少个有效数字?“零还是无限?”迈克尔·博格沃德,epsilon到底是什么?在比较中,0.0001的值实际上是多少?通过测试,我可以找到适用于我的测试数据的合适的ε值(预期为true,预期为false),但我对这个参数不是100%清楚。@Samuel:epsilon是一个相对误差,即ε为0.01意味着两个值之间的差值必须小于1%。但是如果一个值是0,这就没有意义了,所以在这种情况下,我要求另一个值小于ε平方。这是相当武断的;因此,一个普遍有用的比较函数可能不存在的结论。@Michael Bordwardt,谢谢,这是一个很好的解释。我理解并同意你关于通用比较函数的说法,但不幸的是,这是一个库,而不是一个特定的企业应用程序,所以我正在寻找尽可能通用的东西。我还在做更多的测试,您的解决方案和BRETS(更简单、更不整洁)解决方案似乎在相同的情况下工作,但在相同的情况下失败。@Samuel:事实上,这两种方法测试的东西或多或少是相同的,尽管我不希望它们表现出相同的程度。我只是想确认一下,我注意到我的测试套件中缺少了一些东西:你们有比较正负零、无穷大和南的测试用例吗?@Samuel:谢谢,我的地址是brazzy@gmail.com-这些情况最有可能通过以下方式解决: