以下测试将在C#
Assert.AreEqual<double>(10.0d, 16.1d - 6.1d);
问题似乎是浮点错误。
16.1d - 6.1d == 10.000000000000002
这使我在编写使用double
的代码的单元测试时感到头痛。有办法解决这个问题吗?
答案 0 :(得分:5)
十进制系统和双精度的二进制表示之间没有确切的转换(请参阅下面@PatriciaShanahan关于原因的优秀评论)。
在这种情况下,数字的.1部分是问题,它不能用双精度有限地表示(如1/3不能有限地精确表示为十进制数)。
用于解释所发生情况的代码段:
double larger = 16.1d; //Assign closest double representation of 16.1.
double smaller = 6.1; //Assign closest double representation of 6.1.
double diff = larger - smaller; //Assign closest diff between larger and
//smaller, but since a smaller value has a
//larger precision the result will have better
//precision than larger but worse than smaller.
//The difference shows up as the ...000002.
在比较双打时,始终使用Assert.Equal
overload delta
参数。
或者,如果您确实需要精确的十进制转换,请使用decimal
数据类型,该数据类型具有另一个二进制表示形式,并且在您的示例中将返回10
。
答案 1 :(得分:2)
浮点数是基于指数的实际值的估计值,因此测试失败正确。如果您需要两个十进制数的精确等价,则可能需要检查十进制数据类型。
答案 2 :(得分:1)
如果您使用的是NUnit,请使用Within
选项。您可以在此处找到其他信息:http://www.nunit.org/index.php?p=equalConstraint&r=2.6.2。
答案 3 :(得分:0)
我赞同安德斯阿贝尔。使用浮点数表示将无法实现此目的。
在IEE 1985-754的直接结果中只有可以表示的数字
可以存储并精确计算(只要选择的位数允许)。
例如:
1024 * 1.75 * 183.375 / 1040.0675&lt; - 将被精确地存储
10 / 1.1&lt; - 不会精确地存储
如果您对有理数的精确表示不感兴趣,可以使用分数编写自己的数字实现。
这可以通过保存分子,分母和符号来完成。然后需要执行乘法,减法等操作(很难确保良好的性能)。 toString() - 方法看起来像这样(我假设cachedRepresentation,cachedDotIndex和cachedNumerator是成员变量)
public String getString(int digits) {
if(this.cachedRepresentation == ""){
this.cachedRepresentation += this.positiveSign ? "" : "-";
this.cachedRepresentation += this.numerator/this.denominator;
this.cachedNumerator = 10 * (this.numerator % this.denominator);
this.cachedDotIndex = this.cachedRepresentation.Length;
this.cachedRepresentation += ".";
}
if ((this.cachedDotIndex + digits) < this.cachedRepresentation.Length)
return this.cachedRepresentation.Substring(0, this.cachedDotIndex + digits + 1);
while((this.cachedDotIndex + digits) >= this.cachedRepresentation.Length){
this.cachedRepresentation += this.cachedNumerator / this.denominator;
this.cachedNumerator = 10 * (this.cachedNumerator % denominator);
}
return cachedRepresentation;
}
这对我有用。在操作本身有很长的数字我遇到了一些太小的数据类型的问题(通常我不使用c#)。我认为对于经验丰富的c#-developer来说,实现这一点应该没有问题,没有小数据类型的问题。
如果你想实现这个,你应该在初始化时和使用euclids最大公共分割器的操作之前缩小分数。
非有理数可以(在每种情况下我都知道)由算法指定,该算法尽可能接近精确表示(并且计算机允许)。