C语言 检查浮点数是否为整数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5796983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Checking if float is an integer
提问by sidyll
How can I check if a floatvariable contains an integer value? So far, I've been using:
如何检查float变量是否包含整数值?到目前为止,我一直在使用:
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.
但我想知道是否有更好的解决方案,或者这个解决方案是否有任何(或许多)缺点。
采纳答案by Marc Mutz - mmutz
Apart from the fine answers already given, you can also use ceilf(f) == for floorf(f) == f. Both expressions return trueif fis an integer. They also returnfalsefor NaNs (NaNs always compare unequal) and truefor ±infinity, and don't have the problem with overflowing the integer type used to hold the truncated result, because floorf()/ceilf()return floats.
除了已经给出的好答案外,您还可以使用ceilf(f) == f或floorf(f) == f。两个表达式都返回trueiff是一个整数。它们还返回falseNaN(NaN 总是比较不相等)和true±infinity,并且没有溢出用于保存截断结果的整数类型的问题,因为floorf()/ ceilf()return floats。
回答by Jason C
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 coulduse roundf, like this:
请记住,这里的大多数技术都是有效的,假设由于先前计算导致的舍入误差不是一个因素。例如,您可以roundf像这样使用:
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:
这种技术和其他类似技术(例如ceilf,强制转换为long等)的问题在于,虽然它们对整数常量很有效,但如果数字是受浮点舍入影响的计算的结果,它们将失败-关闭错误。例如:
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)20should equal 3, because the actual calculation result ended up being 2.9999992847442626953125.
打印“分数”,即使 (3 1/20) 20应该等于 3,因为实际计算结果最终是2.9999992847442626953125。
Any similar method, be it fmodfor 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:
任何类似的方法,fmodf无论是什么,都受制于这一点。在执行复杂或易于舍入的计算的应用程序中,通常您想要做的是为构成“整数”的内容定义一些“容差”值(这通常适用于浮点相等比较)。我们通常将这种容差称为epsilon。例如,假设我们会原谅计算机高达 +/- 0.00001 的舍入误差。然后,如果我们正在测试z,我们可以选择 0.00001 的 epsilon 并执行以下操作:
if (fabsf(roundf(z) - z) <= 0.00001f) {
printf("integer\n");
} else {
printf("fraction\n");
}
You don't really want to use ceilfhere because e.g. ceilf(1.0000001)is 2 not 1, and ceilf(-1.99999999)is -1 not -2.
你真的不想在ceilf这里使用,因为例如ceilf(1.0000001)是 2 不是 1,ceilf(-1.99999999)是 -1 不是 -2。
You could use rintfin place of roundfif you prefer.
如果您愿意,可以使用rintf代替roundf。
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.
选择适合您的应用的容差值(是的,有时零容差是合适的)。有关更多信息,请查看这篇关于比较浮点数的文章。
回答by DavidN
stdlib float modf (float x, float *ipart) splits into two parts, check if return value (fractional part) == 0.
stdlib float modf (float x, float *ipart) 分成两部分,检查返回值(小数部分)== 0。
回答by Ignacio Vazquez-Abrams
if (fmod(f, 1) == 0.0) {
...
}
Don't forget math.hand libm.
不要忘记math.h和libm。
回答by R.. GitHub STOP HELPING ICE
if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
回答by Controllerface
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.
我不是 100% 确定,但是当您将 f 转换为 int 并从 f 中减去它时,我相信它会转换回浮点数。在这种情况下,这可能无关紧要,但是如果您出于某种原因期望它是 int,则可能会出现问题。
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.
我不知道它本身是否是一个更好的解决方案,但是您可以改用模数数学,例如:
float f = 4.5886;
bool isInt;
isInt = (f % 1.0 != 0) ? false : true;
根据您的编译器,您可能需要或不需要 1 后的 .0,整个隐式转换再次起作用。在此代码中,如果小数点右边全为零,则 bool isInt 应为真,否则为假。
回答by kanna
#define twop22 (0x1.0p+22)
#define ABS(x) (fabs(x))
#define isFloatInteger(x) ((ABS(x) >= twop22) || (((ABS(x) + twop22) - twop22) == ABS(x)))

