Проверка, является ли число с плавающей точкой целым числом - PullRequest
62 голосов
/ 27 апреля 2011

Как я могу проверить, содержит ли переменная float целочисленное значение?До сих пор я использовал:

float f = 4.5886;
if (f-(int)f == 0)
     printf("yes\n");
else printf("no\n");

Но мне интересно, есть ли лучшее решение, или у этого есть какие-либо (или много) недостатки.

Ответы [ 7 ]

66 голосов
/ 27 апреля 2011

Помимо точных ответов, которые вы уже дали, вы также можете использовать ceilf(f) == f или floorf(f) == f.Оба выражения возвращают true, если f является целым числом.Они также возвращают false для NaN ( NaN всегда сравнивают неравномерно ) и true для ± бесконечности, и не имеют проблемы с переполнением целочисленного типа, используемого для хранения усеченного результата, потому что floorf() / ceilf() возврат float с.

16 голосов
/ 13 августа 2014

Имейте в виду, что большинство методов здесь действительны, если допустить, что ошибка округления из-за предыдущих вычислений не является фактором. Например. Вы могли бы использовать roundf, например:

float z = 1.0f;

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Проблема с этим и другими подобными методами (такими как ceilf, приведение к long и т. Д.) Заключается в том, что, хотя они отлично работают для констант с целыми числами, они потерпят неудачу, если число является результатом расчет, который был подвержен ошибке округления с плавающей запятой. Например:

float z = powf(powf(3.0f, 0.05f), 20.0f);

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Печатает «дробь», даже если (3 1/20 ) 20 должно равняться 3, поскольку фактический результат вычисления в итоге составил 2.9999992847442626953125 .

Любой подобный метод, будь то fmodf или какой-либо другой, подпадает под это. В приложениях, которые выполняют сложные или склонные к округлению вычисления, обычно требуется определить некоторое значение «допусков» для того, что составляет «целое число» (это в общем случае выполняется для сравнения на равенство с плавающей запятой). Мы часто называем это терпимость эпсилон . Например, допустим, что мы простим компьютер за ошибку округления до +/- 0,00001. Затем, если мы тестируем z, мы можем выбрать эпсилон 0,00001 и сделать:

if (fabsf(roundf(z) - z) <= 0.00001f) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Вы действительно не хотите использовать ceilf здесь, потому что, например, ceilf(1.0000001) - это 2, а не 1, а ceilf(-1.99999999) - это -1, а не -2. ​​

Вы можете использовать rintf вместо roundf, если хотите.

Выберите значение допуска, которое подходит для вашего приложения (и да, иногда подходит нулевое отклонение). Для получения дополнительной информации, ознакомьтесь с этой статьей на сравнение чисел с плавающей точкой .

9 голосов
/ 27 апреля 2011

stdlib float modf (float x, float * ipart) разбивается на две части, проверьте, возвращаемое значение (дробная часть) == 0.

7 голосов
/ 27 апреля 2011
if (fmod(f, 1) == 0.0) {
  ...
}

Не забудьте math.h и libm.

4 голосов
/ 27 апреля 2011
if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
0 голосов
/ 30 ноября 2012
#define twop22 (0x1.0p+22)
#define ABS(x) (fabs(x))
#define isFloatInteger(x) ((ABS(x) >= twop22) || (((ABS(x) + twop22) - twop22) == ABS(x)))
0 голосов
/ 27 апреля 2011

Я не уверен на 100%, но когда вы приводите f к int и вычитаете его из f, я полагаю, что он возвращается к float.Это, вероятно, не имеет значения в этом случае, но это может привести к проблемам в будущем, если вы ожидаете, что это будет int по какой-то причине.

Я не знаю, является ли это лучшим решением само по себе,но вместо этого вы можете использовать модуль modular math, например: float f = 4.5886; bool isInt; isInt = (f % 1.0 != 0) ? false : true; , в зависимости от вашего компилятора, вам может понадобиться или нет .0 после 1, опять же, в игру вступает целое неявное приведение типов.В этом коде значение boIl isInt должно быть истинным, если справа от десятичной точки установлены все нули, и ложным в противном случае.

...