开发者

Validate double value range and step

I'm trying to construct an algorithm that validates that a double value is a member of a range defined with min, max and step values. The problem is checking that the value obeys the step rule. For integers this can be easily done:

 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;  
 }

This however doesn't work for double values. I know that this at least partly is for precision reasons and I tried hacking a solution by multiplying all the values by a very high number and convert them to longs. This didn't work for all the values though, and neither did allowing a small deviance from 0 when checking the remainder. Has anyone had this problem and come up with a good solution? Below is an example and test featuring the non-working validation method.

One method of doing this would be to start at the min value and increment it by step until it is equal to or greater that the input value, but apart from beeing an ugly solution, this could be a potential bottleneck in my app, so I really want to avoid it.

I'm grateful for any pointers...

Regards / Henrik

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;
}

}


If value follows the step rule, then (value - min)/step should be an integer. You can therefore check how close it is to the nearest integer, and decide if the distance is significant or not.

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


Apart from being not so elegant, and maybe being slow, adding step continuously to get close to the number being checked will result in less accurate calculations because floating-point errors tend to accumulate.

I don't know Java well, but an algorithm to do this would be to take the ratio: (value-min)/step, round it to the nearest integer n, and then calculate v = min+step*n. If v and value are "close enough", then you can mark value as valid.

To test for "close enough" floating-point values, one should use a relative and an absolute tolerance. For example, the package fcmp implements a fairly good algorithm to compare floating-point values.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜