[英]Why does this unit test fail when comparing two doubles?
我在vb.net中有以下代码来计算税前税额:
Public Shared Function CalculateRateBeforeTax(ByVal rate As Decimal, ByVal tax As Decimal) As Decimal
Dim base As Decimal = rate / (1 + (tax / 100.0))
Return Math.Round(base,2)
End Function
我设置的一些场景是:
费率= 107,税= 7%,基数= 100
费率= 325,税= 6.5%,基数= 305.16
费率= 215,税= 125%,基数= 95.55
我使用c#和使用nunit测试框架将上述场景放入一些单元测试中。 第一个场景通过,但另一个失败,我不知道如何让它通过。 这是我的测试:
[TestFixture]
class TaxTests
{
[Test]
public void CalculateRateBeforeTax_ShouldReturn100_WhenRateIs107AndTaxIs7Percent()
{
decimal expected = 100.0m;
decimal actual = TaxUtil.CalculateRateBeforeTax(107.0m, 7.0m);
Assert.AreEqual(expected,actual);
}
[Test]
public void CalculateRateBeforeTax_ShouldReturn305point16_WhenRateIs325AndTaxIs6point5Percent()
{
decimal expected = 305.16m;
decimal actual = TaxUtil.CalculateRateBeforeTax(325.0m, 6.5m);
Assert.AreEqual(expected, actual);
}
[Test]
public void CalculateRateBeforeTax_ShouldReturn95point55_WhenRateIs215AndTaxIs125Percent()
{
decimal expected = 95.55m;
decimal actual = TaxUtil.CalculateRateBeforeTax(215.0m, 125.0m);
Assert.AreEqual(expected, actual);
}
}
正如我之前所说,第一次测试通过,但其他测试的结果是:
第二次测试预计305.1600000000000003d但是:305.1643192488263d
第三次测试预计95.54999999999997但是:95.55555555555555557d
只需拿出一个计算器并输入以下内容:325 /(1 +(6.5 / 100.0))
结果是305.164319 ...
然后你问305.164319 ......是否等于305.16。 测试显然失败了,他们的数字不一样。
现在,如果你想知道为什么你的数字略有不同,比如305.1600000000000003而不是305.16,这是因为Double类型有一些精度损失。 您可以使用Decimal类型以获得更高的精度。
但最重要的问题是CalculateRateBeforeTax返回的值没有被正确截断,以达到精确度。 你只需截断两个小数,如下所示:
Dim rounded As Decimal = Math.Floor(base * 100) / 100
现在通过改变Double类型的Decimal类型,您的Assert应该可以工作。
恭喜。 您的单元测试实际上已经完成了他们应该做的事情,并且发现了您正在测试的代码的错误。
你有舍入错误。 不幸的是,这是由您尝试单元测试的VB.NET代码而不是实际测试中的代码引起的。
您需要使用更精确的数据类型。 我建议替换你使用Double
with Decimal
。
您无法保证浮点数彼此相同,即使它们看起来如此。
它取决于许多因素,如处理器,体系结构等。正如Justin所说,如果需要精度,请使用decimal。
看看Jon Skeets优秀博客文章: http : //csharpindepth.com/Articles/General/FloatingPoint.aspx
虽然其他海报是正确的说明你应该使用Decimal
而不是Double
,这不是你观察到的问题的原因。
观察到的问题是由舍入代码中的逻辑错误引起的。 您需要查找如何正确舍入此类值。 这是一个法律问题,而不是数学问题。
另一个奇怪的事情是你的CalculateRateBeforeTax
其返回值四舍五入为一个整数值,但是你发布的值似乎是在没有舍入的情况下计算的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.