如何检查float
变量是否包含整数值?到目前为止,我一直在使用:
float f = 4.5886;
if (f-(int)f == 0)
printf("yes\n");
else printf("no\n");
但我想知道是否有更好的解决方案,或者这个解决方案是否存在任何(或许多)缺点。
答案 0 :(得分:66)
除了已经给出的优秀答案外,您还可以使用ceilf(f) == f
或floorf(f) == f
。如果true
是整数,则两个表达式都返回f
。对于NaNs(NaNs always compare unequal)和false
,它们也返回true
以获得±无穷大,并且没有溢出用于保存截断结果的整数类型的问题,因为{{1 } / floorf()
返回ceilf()
s。
答案 1 :(得分:16)
请记住,此处的大多数技术都是有效的,假设由于先前计算而导致的舍入误差不是一个因素。例如。你可以使用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
还是其他什么,都受此限制。在执行复杂或易于舍入的计算的应用程序中,通常您要做的是为构成“整数”的内容定义一些“容差”值(这通常用于浮点相等比较)。我们经常将此容差称为 epsilon 。例如,假设我们原谅计算机最多+/- 0.00001舍入误差。然后,如果我们正在测试z
,我们可以选择0.00100的epsil并执行:
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
。
选择适合您的应用的公差值(是的,有时零容差是合适的)。有关详细信息,请查看comparing floating-point numbers上的这篇文章。
答案 2 :(得分:8)
stdlib float modf(float x,float * ipart)分为两部分,检查返回值(小数部分)== 0.
答案 3 :(得分:7)
if (fmod(f, 1) == 0.0) {
...
}
不要忘记math.h
和libm
。
答案 4 :(得分:4)
if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
答案 5 :(得分:0)
我不是100%肯定,但是当你把f转换为int,并从f中减去它时,我相信它会被抛回到浮点数。在这种情况下,这可能无关紧要,但如果你因为某种原因期望它成为一个int,它可能会出现问题。
我不知道这本身是否是更好的解决方案,但您可以使用模数数字,例如:
float f = 4.5886;
bool isInt;
isInt = (f % 1.0 != 0) ? false : true;
根据你的编译器,你可能需要或不需要.0之后,再次整个隐式转换事件发挥作用。在这段代码中,如果小数点的右边全为零,则bool isInt应为true,否则为false。
答案 6 :(得分:0)
#define twop22 (0x1.0p+22)
#define ABS(x) (fabs(x))
#define isFloatInteger(x) ((ABS(x) >= twop22) || (((ABS(x) + twop22) - twop22) == ABS(x)))
答案 7 :(得分:0)
这涉及计算四舍五入。您可以根据需要设置epsilon:
bool IsInteger(float value)
{
return fabs(ceilf(value) - value) < EPSILON;
}