Проверить двойной диапазон значений и шаг - PullRequest
1 голос
/ 22 декабря 2009

Я пытаюсь построить алгоритм, который проверяет, что двойное значение является членом диапазона, определенного с минимальными, максимальными и пошаговыми значениями. Проблема заключается в проверке того, что значение подчиняется правилу шага. Для целых чисел это легко сделать:

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

Это, однако, не работает для двойных значений. Я знаю, что это, по крайней мере, частично из соображений точности, и я попытался взломать решение, умножив все значения на очень большое число и преобразовав их в длинные. Это не сработало для всех значений, хотя и не допускало небольшого отклонения от 0 при проверке остатка. Кто-нибудь имел эту проблему и придумал хорошее решение? Ниже приведен пример и тест с использованием нерабочего метода проверки.

Один из способов сделать это состоит в том, чтобы начать с минимального значения и постепенно увеличивать его до тех пор, пока оно не станет равным или превышающим входное значение, но, кроме того, что это уродливое решение, это может стать потенциальным узким местом в моем приложении. Поэтому я очень хочу этого избежать.

Я благодарен за любые указатели ...

С уважением / 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;
}

}

Ответы [ 2 ]

3 голосов
/ 22 декабря 2009

Если value следует правилу шага, тогда (value - min)/step должно быть целым числом. Поэтому вы можете проверить, насколько близко оно к ближайшему целому числу, и решить, является ли расстояние значительным или нет.

double ratio = (value-min)/step;
double distance = Math.Abs(ratio - Math.Round(ratio,0));
return distance < treshold;
1 голос
/ 22 декабря 2009

Помимо не слишком элегантного и, возможно, медленного, добавление step непрерывно, чтобы приблизиться к проверяемому числу, приведет к менее точным вычислениям, так как ошибки с плавающей точкой имеют тенденцию накапливаться.

Я не очень хорошо знаю Java, но алгоритм для этого должен был бы взять соотношение: (value-min)/step, округлить до ближайшего целого числа n, а затем вычислить v = min+step*n. Если v и value «достаточно близко», вы можете пометить value как действительный.

Чтобы проверить «достаточно близкие» значения с плавающей запятой, следует использовать относительный и абсолютный допуск. Например, пакет fcmp реализует довольно хороший алгоритм для сравнения значений с плавающей запятой.

...