2011-03-30 63 views
3

我已經在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

我把ABO使用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

+1

對於貨幣,你應該真的使用十進制 – HadleyHope 2011-03-30 15:25:30

+1

[每個計算機科學家應該知道的有關浮點運算](http://portal.acm.org/citation.cfm?id=103163) – Oded 2011-03-30 15:26:41

回答

6

就掏出計算器,並輸入以下內容:如果305.164319 325 /(1 +(6.5/100.0))

結果是305.164319 ...

然後你問...等於305.16。測試顯然失敗,他們不是相同的數字。

現在,如果你想知道爲什麼你的數字略有不同,比如305.1600000000000003而不是305.16,這是因爲Double類型會導致一些精度損失。您可以使用Decimal類型來獲得更高的精度。

但最重要的問題是CalculateRateBeforeTax返回的值未被正確截斷以精確到分。你只需要像這樣截斷兩位小數:

Dim rounded As Decimal = Math.Floor(base * 100)/100 

現在通過更改雙精度類型的十進制類型你的斷言應該工作。

+1

有一個輪的超載取所需的小數位數。所以你可以扔掉* 100/100的東西。 – CodesInChaos 2011-03-30 15:43:18

+0

謝謝我只是做了改變。 – 2011-03-30 15:43:55

+0

Math.Round(base,2)爲什麼不是305.l64319到305.16? – Xaisoft 2011-03-30 15:44:24

2

恭喜。你的單元測試實際上已經完成了他們應該做的事情,並發現你正在測試的代碼存在一個錯誤。

您有四捨五入錯誤。不幸的是,這是由你正在嘗試單元測試的VB.NET代碼造成的,而不是你實際測試中的代碼。

您需要使用更精確的數據類型。我建議用Decimal代替Double的使用。

+0

我強烈懷疑他的錯誤是由雙精度限制造成的。當然他應該使用'Decimal',但我認爲這不能解決他的問題。 – CodesInChaos 2011-03-30 15:29:05

+0

我改爲十進制,但第二次和第三次測試仍然失敗。我甚至試圖做Math.Round(305.16432,2)來獲得305.16,但它仍然返回整個數字。 – Xaisoft 2011-03-30 15:34:26

+0

@CodeInChaos - 是什麼讓你認爲這是另一個問題造成的? OP(以及它們是單元測試的代碼)使用雙精度執行了很多計算,並且發佈的結果肯定看起來像是由於精度損失導致的舍入誤差。 – 2011-03-30 15:35:11

0

即使出現這種情況,您也無法保證浮點數彼此相同。

它取決於許多因素,如處理器,體系結構等。正如賈斯汀所說,如果需要精度,則使用十進制。

看一看喬恩長柄水杓優秀的博客文章:http://csharpindepth.com/Articles/General/FloatingPoint.aspx

+0

雖然這是真的,但我不認爲這確實解釋了OP的問題。 – CodesInChaos 2011-03-30 15:40:58

0

而其他海報右側,說明你應該使用的Decimal代替Double這是不是你的觀察問題的原因。

觀察到的問題是由舍入代碼中的邏輯錯誤引起的。您需要查看如何正確舍入這些值。這是一個法律問題,而不是數學問題。

另一個奇怪的是,您的CalculateRateBeforeTax將其返回值舍入爲一個整數值,但是您發佈的值似乎沒有進行舍入計算。

+0

是的,令人困惑的是,Math.Round(x,2)應該將數字四捨五入到小數點後兩位,但它會返回整數,就好像它不是舍入一樣。 – Xaisoft 2011-03-30 15:40:14

+0

即使您修復該問題,您的代碼可能不正確。您需要在規範中查看它,即您的稅法。 – CodesInChaos 2011-03-30 15:45:06

+0

而當我在LinqPad中測試非常相似的代碼時,它的工作原理如預期 – CodesInChaos 2011-03-30 15:47:22

相關問題