Я работаю над кодом, где мне нужно проверить, действительно ли определенная переменная, которая может принимать двойное значение, принимает целочисленное значение. Я считаю, что двойная переменная принимает целочисленное значение, если оно находится в пределах допуска целого числа. Этот допуск составляет 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.
Любые указатели будут с благодарностью!
Да, с плавающей запятой сложно. Просто так 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);
}