以下测试将失败C#
Assert.AreEqual<double>(10.0d, 16.1d - 6.1d);
问题似乎是一个浮点错误。
16.1d - 6.1d == 10.000000000000002
这让我在为使用double
. 有没有办法来解决这个问题?
以下测试将失败C#
Assert.AreEqual<double>(10.0d, 16.1d - 6.1d);
问题似乎是一个浮点错误。
16.1d - 6.1d == 10.000000000000002
这让我在为使用double
. 有没有办法来解决这个问题?
十进制系统和双精度的二进制表示之间没有精确的转换(请参阅下面@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
重载。delta
或者,如果您确实需要精确的十进制转换,请使用decimal
具有另一种二进制表示形式的数据类型,并且将10
在您的示例中完全返回。
浮点数是基于指数对实际值的估计,因此测试正确失败。如果您需要两个十进制数的精确等价,您可能需要检查十进制数据类型。
如果您使用的是 NUnit,请使用该Within
选项。您可以在这里找到更多信息:http ://www.nunit.org/index.php?p=equalConstraint&r=2.6.2 。
我同意安德斯·阿贝尔的观点。没有办法使用浮点数表示来做到这一点。
在IEE 1985-754的直接结果中,只有可以表示的数字可以
精确存储和计算(只要选择的位数允许)。
例如:
1024 * 1.75 * 183.375 / 1040.0675 <-- 将精确存储
10 / 1.1 <-- 不会精确存储
如果您对有理数的精确表示几乎不感兴趣,您可以使用分数编写自己的数字实现。
这可以通过保存分子、分母和符号来完成。然后需要实现乘法、减法等操作(很难确保良好的性能)。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# 开发人员来说,在没有小数据类型问题的情况下实现这一点应该没有问题。
如果你想实现这一点,你应该在初始化和操作之前使用 euclids 最大通用除法器对分数进行缩小。
非有理数可以(在我知道的每种情况下)由一种算法指定,该算法尽可能接近您想要的精确表示(并且计算机允许)。