检查float是否为整数

sid*_*yll 65 c floating-point int

如何检查float变量是否包含整数值?到目前为止,我一直在使用:

float f = 4.5886;
if (f-(int)f == 0)
     printf("yes\n");
else printf("no\n");
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有更好的解决方案,或者这个解决方案是否存在任何(或许多)缺点.

Mar*_*utz 66

除了已经给出的好答案,你也可以使用ceilf(f) == ffloorf(f) == f.true如果f是整数,则两个表达式都返回.它们也返回falseNaNs(NaNs总是比较不相等)和true±无穷大,并且没有溢出用于保存截断结果的整数类型的问题,因为floorf()/ ceilf()return floats.

  • 虽然这有效,但由于需要更改和恢复舍入模式,`ceilf`和`floorf`在至少某些拱门(主要是x86)上的操作不必要地昂贵.更快的测试是`rintf(f)== f`.使用`-fno-math-errno`,GCC会将`rintf`编译为单个内联指令. (3认同)
  • @R ..我是否正确假设`nearbyintf`会在没有异常和标志的情况下做同样的事情? (3认同)

Jas*_*n C 19

请记住,此处的大多数技术都是有效的,假设由于先前计算而导致的舍入误差不是一个因素.你可以使用roundf,像这样:

float z = 1.0f;

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}
Run Code Online (Sandbox Code Playgroud)

这个和其他类似技术(例如ceilf,转换为long等)的问题在于,虽然它们对于整数常量很有效,但如果数字是一个受浮点圆计算的结果,它们将会失败 - 错误.例如:

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

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}
Run Code Online (Sandbox Code Playgroud)

打印"分数",即使(3 1/20)20应该等于3,因为实际计算结果最终为2.9999992847442626953125.

任何类似的方法,fmodf无论是它还是其他方式都受此约束.在执行复杂或易于舍入的计算的应用程序中,通常您要做的是为构成"整数"的内容定义一些"容差"值(这通常用于浮点相等比较).我们经常称这种公差为epsilon.例如,假设我们原谅计算机最多+/- 0.00001舍入误差.然后,如果我们正在测试z,我们可以选择0.00001的epsil并执行:

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

你真的不想在ceilf这里使用,因为例如ceilf(1.0000001)2不是1,而ceilf(-1.99999999)-1不是-2.

如果您愿意,可以使用rintf它代替roundf.

选择适合您的应用的公差值(是的,有时零容差是合适的).有关更多信息,请查看有关比较浮点数的文章.


Dav*_*idN 9

stdlib float modf(float x,float*ipart)分为两部分,检查返回值(小数部分)== 0.

  • @mmutz:我说我应该戴眼镜吗? (2认同)

Ign*_*ams 8

if (fmod(f, 1) == 0.0) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

别忘了math.hlibm.

  • 这是有效的,但原则上`fmod`是一个相当昂贵的操作. (3认同)

R..*_*R.. 6

if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
Run Code Online (Sandbox Code Playgroud)

  • @mangledorf:您的转换无效。如果值不能表示为 `long`,`(long)f` 会调用未定义的行为。因此,您必须首先进行比较以确保安全。 (3认同)
  • 只是为了以防万一有人找到这个答案并尝试将其应用于“双重”。 (2认同)