2014-10-01 73 views
2

我將舉一個我的實際情況的簡單例子:Java,BigDecimal:如何對舍入錯誤進行單元測試?

假設我必須在Java中實現一些代碼來計算Weighted arithmetic mean。我給出了兩個浮點值數組(表示爲雙精度值),每個數值長度相同,第一個包含值,第二個值包含它們各自的權重。

讓我們也說,我做了一些實現,它返回一個浮點值(也是雙)表示輸入值的加權算術平均值:

public static double calculateWeightedArithmeticMean(double[] values, 
     double[] weights) { 

    if(values.length != weights.length) { 
     throw new IllegalArgumentException(); 
    } 

    if(values.length == 0) { 
     return 0; 
    } 

    if(values.length == 1) { 
     return new BigDecimal(values[0]).setScale(1, RoundingMode.HALF_UP). 
       doubleValue(); 
    } 

    BigDecimal dividend = BigDecimal.ZERO; 
    BigDecimal divisor = BigDecimal.ZERO; 
    for(int i = 0; i < values.length; i++) { 
     dividend = dividend.add(new BigDecimal(values[i]). 
       multiply(new BigDecimal(weights[i]))); 
     divisor = divisor.add(new BigDecimal(weights[i])); 
    } 
    if(dividend.compareTo(BigDecimal.ZERO) == 0) { 
     return 0d; 
    } 
    return dividend.divide(divisor, 1, RoundingMode.HALF_UP).doubleValue(); 
} 

我寫單元測試經過幾個值(像3個值+3個權重)。我首先手動計算加權算術平均值(使用計算器),然後編寫一個單元測試,檢查我的代碼是否返回該值。

我相信這樣的測試不適用於由於舍入誤差而使用的值的數量大得多的情況。也許我已經實現的代碼對於3個值+3的權重(對於給定的精度)運行良好,因爲在這種情況下舍入誤差小於精度,但很可能捨入誤差變得大於期望的精度1000值+ 1000重量。

我的問題是:

  • 應該我也寫一個單元測試,用來檢查一個非常大的數字值(一個「最壞的情況」生產使用)?
  • 如果我應該如何寫它?如何獲得正確的值,以便我可以在測試中使用它(計算2x1000值的手段似乎是一種壞主意,即使使用Weighted mean calculator ...)?
  • 也是如此相似的場景:計算geometric mean,等...

回答

1

當編寫單元測試時,你總是有地方放棄。關鍵是要放棄的時候,你有信心,你知道足夠:-)

在你的情況,一些簡單的測試情況是:

  • 空數組
  • 創建一個使用第二算法精確算術(如BigDecimal輸入數組)來計算所選輸入的誤差範圍
  • 兩個數組填充相同的值。這樣,你就知道結果(它應該和第一對一樣)。
    • 試圖找到一對引起大的舍入誤差的數字(如1/10,0.1/1,0.2/2,其中所有最終成爲0.1,不能表示正確使用雙; see here)的
  • 創建包含隨機差異的輸入數組(即+ - 1%* rand())。當你增長輸入數組時,這些應該甚至會出現。

當比較的結果,使用assertEquals(double, double, double)其中前兩個是值進行比較,最後一個是精度(1e-3爲逗號後3位數字)。

最後,您需要使用該算法並查看它的行爲。當您發現問題時,請爲此特定案例添加一個測試用例。

+0

謝謝,這是一個很棒的答案。 – 2014-10-01 10:09:38

1

是的,你應該。測試(應該)總是涉及邊界值。

您可以提供一個epsilon邊界,您聲明答案是(近似)正確的。

+0

我同意你關於測試邊界的一般說明。然而,這真的是我的問題的一部分,我不確定在這裏「參數的數目」是否可以看作是「邊界情況」... – 2014-10-01 10:14:52

+1

您可以用新的double [Integer.MAX_VALUE]初始化參數。 – user 2014-10-01 10:17:42

+0

這是一個非常好的建議(沒有想到那樣的邊界)。但是,我怎麼知道20億以上的數值和權重的正確加權平均值是多少,所以我可以在我的測試中查看它? – 2014-10-01 10:20:24