Проверьте, является ли переданный двойной аргумент "достаточно близким", чтобы считаться целым

Я работаю над кодом, в котором мне нужно проверить, приняла ли определенная переменная, которая может принимать двойное значение, целочисленное значение. Я считаю, что двойная переменная принимает целочисленное значение, если оно находится в пределах допуска целого числа. Этот допуск составляет 1е-5.

Вот мой код:

#define SMALL 1e-5
//Double that attains this is considered non zero. Strictly Less than this is 0

int check_if_integer(double arg){
//returns 1 if arg is close enough to an integer
//returns 0 otherwise
    if(arg - (int)arg >= SMALL){
        if(arg + SMALL > (int)(arg+1.0)){
            return(1);
//Code should have reached this point since
//arg + SMALL is 16.00001 
//while (int)(arg+1.0) should be 16
//But the code seems to evaluate (int)(arg+1.0) to be 17
        }
    }
    else{
        return(1);
    }
    return(0);
}

int main(void){

    int a = check_if_integer(15.999999999999998);

}

К сожалению, при передаче аргумента 15.999999999999998 функция возвращает 0. То есть она считает аргумент дробным, в то время как ей следовало бы вернуть 1, указывающий, что аргумент "достаточно близок" к 16.

Я использую VS2010 Professional.

Любые указатели будут с благодарностью!

2 ответа

Решение

Да, с плавающей запятой сложно. Просто так 15.999999999999998 < 16.0это не значит 15.999999999999998 + 1.0 < 17.0, Предположим, у вас есть десятичный тип с плавающей запятой с тремя цифрами точности. Какой результат вы получаете за 9.99 + 1.0 в точности этого типа? Математический результат будет 10.99и округляется до точности этого типа дает 11.0, Двоичная с плавающей точкой имеет ту же проблему.

В этом конкретном случае вы можете изменить (int)(arg+1.0) в (int)arg+1, (int)arg является точным, как и целочисленное сложение.

В дополнение к ответу HVD относительно типов; также нецелесообразно добавлять / вычитать маленькие двойники к / из больших двойников из-за способа их внутреннего представления.

Простая работа, которая позволяет избежать обеих проблем:

if (abs(arg - round(arg)) <= SMALL) {
  return (1);
} else {
  return (0);
}
Другие вопросы по тегам