Имейте в виду, что большинство методов здесь действительны, если допустить, что ошибка округления из-за предыдущих вычислений не является фактором. Например. Вы могли бы использовать 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
, если хотите.
Выберите значение допуска, которое подходит для вашего приложения (и да, иногда подходит нулевое отклонение). Для получения дополнительной информации, ознакомьтесь с этой статьей на сравнение чисел с плавающей точкой .