检查 float 是否为整数

发布于 2024-11-03 15:37:07 字数 206 浏览 3 评论 0原文

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

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

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

How can I check if a float variable contains an integer value? So far, I've been using:

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

But I wonder if there is a better solution, or if this one has any (or many) drawbacks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

只有一腔孤勇 2024-11-10 15:37:07

除了已经给出的好的答案之外,您还可以使用 ceilf(f) == f 或 floorf(f) == f 。如果 f 是整数,则两个表达式都返回 true。对于 NaN,它们还返回 false(NaN 始终比较 unequal) 和 true 的±无穷大,并且不会出现用于保存截断结果的整数类型溢出的问题,因为 floorf() /ceilf() 返回 float

Apart from the fine answers already given, you can also use ceilf(f) == f or floorf(f) == f. Both expressions return true if f is an integer. They also returnfalse for NaNs (NaNs always compare unequal) and true for ±infinity, and don't have the problem with overflowing the integer type used to hold the truncated result, because floorf()/ceilf() return floats.

惯饮孤独 2024-11-10 15:37:07

请记住,假设先前计算引起的舍入误差不是一个因素,那么这里的大多数技术都是有效的。例如,您可以使用roundf,如下所示:

float z = 1.0f;

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

此技术和其他类似技术的问题(例如ceilf,转换为long< /code> 等)的问题是,虽然它们对于整数常量非常有效,但如果该数字是受浮点舍入误差影响的计算结果,它们就会失败。例如:

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

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

打印“分数”,尽管 (31/20)20 应等于 3,因为实际计算结果最终为 2.9999992847442626953125

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

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

选择适合您的应用的容差值(是的,有时零容差是合适的)。有关详细信息,请查看这篇关于比较浮点数的文章。

Keep in mind that most of the techniques here are valid presuming that round-off error due to prior calculations is not a factor. E.g. you could use roundf, like this:

float z = 1.0f;

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

The problem with this and other similar techniques (such as ceilf, casting to long, etc.) is that, while they work great for whole number constants, they will fail if the number is a result of a calculation that was subject to floating-point round-off error. For example:

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

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

Prints "fraction", even though (31/20)20 should equal 3, because the actual calculation result ended up being 2.9999992847442626953125.

Any similar method, be it fmodf or whatever, is subject to this. In applications that perform complex or rounding-prone calculations, usually what you want to do is define some "tolerance" value for what constitutes a "whole number" (this goes for floating-point equality comparisons in general). We often call this tolerance epsilon. For example, lets say that we'll forgive the computer for up to +/- 0.00001 rounding error. Then, if we are testing z, we can choose an epsilon of 0.00001 and do:

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

You don't really want to use ceilf here because e.g. ceilf(1.0000001) is 2 not 1, and ceilf(-1.99999999) is -1 not -2.

You could use rintf in place of roundf if you prefer.

Choose a tolerance value that is appropriate for your application (and yes, sometimes zero tolerance is appropriate). For more information, check out this article on comparing floating-point numbers.

‖放下 2024-11-10 15:37:07
if (fmod(f, 1) == 0.0) {
  ...
}

不要忘记 math.hlibm

if (fmod(f, 1) == 0.0) {
  ...
}

Don't forget math.h and libm.

不念旧人 2024-11-10 15:37:07

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

stdlib float modf (float x, float *ipart) splits into two parts, check if return value (fractional part) == 0.

难以启齿的温柔 2024-11-10 15:37:07
if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
伤感在游骋 2024-11-10 15:37:07

这涉及计算舍入。您根据需要设置 epsilon:

bool IsInteger(float value)
{
    return fabs(ceilf(value) - value) < EPSILON;
}

This deals with computational round-off. You set the epsilon as desired:

bool IsInteger(float value)
{
    return fabs(ceilf(value) - value) < EPSILON;
}
蓝戈者 2024-11-10 15:37:07

我不是 100% 确定,但是当你将 f 转换为 int 并从 f 中减去它时,我相信它会转换回 float 。在这种情况下,这可能并不重要,但如果您出于某种原因期望它是一个 int ,那么它可能会带来问题。

我不知道这本身是否是更好的解决方案,但您可以使用模数数学来代替,例如:
<代码>
浮点数 f = 4.5886;
bool isInt;
isInt = (f % 1.0 != 0) ?假:真;

根据您的编译器,您可能需要或不需要 1 之后的 .0,整个隐式转换再次发挥作用。在此代码中,如果小数点右侧全为零,则 bool isInt 应为 true,否则为 false。

I'm not 100% sure but when you cast f to an int, and subtract it from f, I believe it is getting cast back to a float. This probably won't matter in this case, but it could present problems down the line if you are expecting that to be an int for some reason.

I don't know if it's a better solution per se, but you could use modulus math instead, for example:

float f = 4.5886;
bool isInt;
isInt = (f % 1.0 != 0) ? false : true;

depending on your compiler you may or not need the .0 after the 1, again the whole implicit casts thing comes into play. In this code, the bool isInt should be true if the right of the decimal point is all zeroes, and false otherwise.

独自←快乐 2024-11-10 15:37:07
#define twop22 (0x1.0p+22)
#define ABS(x) (fabs(x))
#define isFloatInteger(x) ((ABS(x) >= twop22) || (((ABS(x) + twop22) - twop22) == ABS(x)))
#define twop22 (0x1.0p+22)
#define ABS(x) (fabs(x))
#define isFloatInteger(x) ((ABS(x) >= twop22) || (((ABS(x) + twop22) - twop22) == ABS(x)))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文