2009-12-22 61 views
1

我試圖構建用於驗證雙值與最小值,最大值和步長值限定的範圍的成員的算法。問題在於檢查值是否符合步驟規則。對於整數,這可以很容易地完成:驗證雙值範圍和步

boolean validate(int value, int min, int step, int max){ 
     return value >= min && 
      value <= max && 

      //Step should be relative to the min value not to 0. 
      (value-min) % step == 0; 
} 

但是,這不適用於雙值。我知道這至少部分是出於精度原因,我試圖通過將所有值乘以非常高的數字來將黑洞解決方案篡改並將它們轉換爲長整型。儘管這並不適用於所有的值,但在檢查餘數時,它們都不允許有小的偏差。有沒有人有這個問題,並提出一個很好的解決方案?下面是一個以非工作驗證方法爲特徵的例子和測試。

這樣做的一種方法是從最小值開始遞增,直到它等於或大於輸入值,但除了一個醜陋的解決方案之外,這可能是我的潛在瓶頸應用程序,所以我真的想避免它。

我對任何指針感激......

祺/亨利克

public class ValidationExample { 

public static void main(String[] args) { 
    /*Range: 
     min -10.5 
     step .3 
     max -5 
    */ 

    //Invalid values 
    double[] a = {-11,-10.6,-10.4,-10.3,-10.1,-10.0,-9.8,-9.7, 
      -9.5,-9.4,-9.2,-9.1,-8.9,-8.8,-8.6,-8.5,-8.3, 
      -8.2,-8,-7.9,-7.7,-7.6,-7.4,-7.3,-7.1,-7.0, 
      -6.8,-6.7,-6.5,-6.4,-6.2,-6.1,-5.9,-5.8,-5.6, 
      -5.5,-5.3,-5.2,-5.0,-4.9,-4.8,2}; 

    //Valid values 
    double[] b = {-10.5,-10.2,-9.9,-9.6,-9.3,-9.0,-8.7,-8.4, 
      -8.1,-7.8,-7.5,-7.2,-6.9,-6.6,-6.3,-6.0,-5.7, 
      -5.4,-5.1}; 

    for(double d : a){ 
     if(validate(d,-10.5,.3,-5)) 
      System.err.println(d + " was considered valid."); 
    } 

    for(double d : b){ 
     if(!validate(d, -10.5,.3,-5)) 
      System.err.println(d + " was considered invalid"); 
    } 

    /* 
    * Range 
    * min 2 
    * step .05 
    * max 3 
    */ 

    //Invalid values 
    double[] c = {1.09,2.055,2.06,2.14,2.16,2.56,2.97,3.05}; 

    //Valid values 
    double[] e = {2.0,2.05,2.1,2.15,2.2,2.25,2.5,2.75,2.95,3.0}; 

    for(double d : c){ 
     if(validate(d,2,.05,3)) 
      System.err.println(d + " was considered valid."); 
    } 

    for(double d : e){ 
     if(!validate(d,2,.05,3)) 
      System.err.println(d + " was considered invalid."); 
    } 

} 

private static boolean 
    validate(double value, double min, double step, double max){ 
    return value >= min && 
      value <= max && 
      (value - min) % step == 0; 
} 

}

+0

問題: - 必須步長正好等於或他們能有什麼不同? - 在第一種情況:你介意有0.299995,而不是0.3? 的條件是什麼?由於條件「雙值是用最小值,最大值和步長值定義的範圍的成員」對於每個雙精度值和步長都是不可能的! – 2010-01-05 16:52:16

回答

3

如果value如下步驟規則,然後(value - min)/step應該是一個整數。因此,您可以檢查它離最近的整數有多近,並確定距離是否顯着。

double ratio = (value-min)/step; 
double distance = Math.Abs(ratio - Math.Round(ratio,0)); 
return distance < treshold; 
+0

這解決了我的問題,並與我所有的測試一起工作。但是,如果有人知道選擇最佳閾值的方式,請分享。我只是在這裏猜... ...) 謝謝! – Bulgur 2009-12-22 13:37:07

+0

參見http://www.ibm.com/developerworks/java/library/j-math2.html,特別'Math.ulp()'。所以,你可以決定ULPS差異是多少給你足夠大,並使用該寬容。 – 2009-12-23 17:03:19

1

除了是不那麼優雅,也許是緩慢的,將step不斷去接近被檢查將導致不準確的計算,因爲浮點錯誤會積累數。

我不太瞭解Java,但是要做到這一點的算法是將比率:(value-min)/step,四捨五入到最接近的整數n,然後計算v = min+step*n。如果vvalue「足夠接近」,那麼你可以標記value爲有效。

爲了測試「足夠接近」浮點值,應使用相對和絕對的寬容。例如,包fcmp實現了一個相當好的算法來比較浮點值。