簡體   English   中英

我應該如何對執行數組數值插值的類進行單元測試?

[英]How should I unit-test a class which performs numeric interpolation of arrays?

我在一個項目中工作,其中一些類執行數值插值,也就是說,給定一組已知位置的點,我可以要求網格節點之間的點的位置,可以這么說。

由於這些方法根據定義不返回精確值,我想知道我應該如何對它們進行單元測試。

例如,下面的代碼測試如果我給它一個類似的零數組,則插值器返回一個零數組,並且它有效,但我懷疑它有效,因為我實際上並沒有在這里重新采樣,只是再次詢問相同的位置。

[TestMethod]
public void Interpolate_ZeroIn_ZeroOut()
{
    var Xvalues = new double[] {1,2,3,4,5,6,7,8,9,10};
    var Yvalues = new double[] {0,0,0,0,0,0,0,0,0,0};

    List<Point> points = 
        Enumerable.Zip(Xvalues, Yvalues, (x,y) => new Point(x,y)).ToList();

    int interpolation_order = 5;

    FourierIterpolator target = new FourierInterpolator(points, interpolation_order);

    var output = Xvalues.Select(p => target.Interpolate(p)).ToList();

    CollectionAssert.AreEqual(output, Yvalues);
}

問題是:通過實際重采樣,新點將在輸入點“之間”,所以我不能使用CollectionAssert.AreEqual 此外,使用一些帶平滑的插值方法,數組將不相等,只有近似值。

所以,我的問題是:

在測試涉及近似/插值的數值方法時推薦使用哪些斷言?

您的插值技術是確定性的嗎? 確定性意味着:如果您的方法使用相同的參數被調用兩次,它會在兩種情況下返回完全相同的結果嗎?)

如果是,

  • 通過您的函數運行一些值,
  • 使用外部方法來驗證結果是否正確(筆和紙,或一些數學工具),
  • 添加這些值作為測試用例。

這將確保測試用例檢測到您的方法的任何重大更改 一個缺點是,如果您改進插值技術,您的案例將失敗,從而產生不同的結果。 這不一定是壞事,因為它會提醒您您的方法現在返回不同的結果。

如果您的插值技術不是確定性的,即,如果它使用一些隨機源,您可能能夠斷言這些值在一些合理的誤差范圍內。

目前很難看到測試的輸入數據是什么。 我建議您使測試數據明確且易於查看。 此外,我認為您不需要 10 或 100 分來驗證您的方法是否有效。 大概 2-3 點就足夠了:

var points = new []{ new Point(0,0), new Point(1,0), new Point(2,0) });

接下來,您應該提供預期值:

double[] expected = { 0.33, 0.66, 1.66 };

最后 - 檢查實際值是否等於或接近預期值:

[TestMethod]
public void Interpolar_ZeroIn_ZeroOut()
{
    var points = new []{ new Point(0,0), new Point(1,0), new Point(2,0) });
    // calculate expected values manually
    double[] expected = { 0.33, 0.66, 1.66 };    
    int ordem = 5;

    var interpolator = new InterpoladorFourier(points, ordem);

    for(int i = 0; i < points.Length; i++)        
       Assert.AreEqual(expected[i], interpolator.Interpolar(points[i].X));
}

如果預期數據不准確,那么您可以為斷言提供增量:

Assert.AreEqual(expected[i], interpolator.Interpolar(points[i].X), 0.01);

或者甚至更好 - 您可以創建以非常易讀的方式創建點的方法:

var points = CreatePoints("0,0", "1,0", "2,0"); 

使用此輔助方法:

private Point[] CreatePoints(params string[] points)
{
    List<Point> result = new List<Point>();

    foreach(var s in points)
    {
        var parts = s.Split(',');
        var x = Double.Parse(parts[0]);
        var y = Double.Parse(parts[1]);            
        var point = new Point(x,y);
        result.Add(point);
    }

    return result.ToArray();
}

我通過谷歌來到這里是因為我自己也在尋找一些答案,但我目前的方法可能比這里提供的方法更好,所以我會分享以供將來參考。

大多數(如果不是全部)插值方法都有相當數量的函數,它們可以完美地或至少達到機器精度。 例如三次樣條,它的多項式達到 3 次。我只是測試合理數量的具有不同系數、不同間隔、不同點數的多項式......如果它接近機器精度,則計算 RMS 誤差並“斷言” (比如 rms_err < 10*eps)。 准確選擇哪些多項式/函數/參數適合此處需要一些關於特定插值方法的知識,可能還有浮點錯誤,但這是可行的。

另一種方法是與具有相同或相似實現的可用庫進行比較,或者直接導出僅使用庫的值。 例如,我使用可用的 1D 實現測試了我的 2D 插值實現,這些實現使用相同的方法,當然沿着一個維度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM