检查 float 是否为整数
如何检查 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
除了已经给出的好的答案之外,您还可以使用 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
orfloorf(f) == f
. Both expressions returntrue
iff
is an integer. They also returnfalse
for NaNs (NaNs always compare unequal) andtrue
for ±infinity, and don't have the problem with overflowing the integer type used to hold the truncated result, becausefloorf()
/ceilf()
returnfloat
s.请记住,假设先前计算引起的舍入误差不是一个因素,那么这里的大多数技术都是有效的。例如,您可以使用
roundf
,如下所示:此技术和其他类似技术的问题(例如
ceilf
,转换为long< /code> 等)的问题是,虽然它们对于整数常量非常有效,但如果该数字是受浮点舍入误差影响的计算结果,它们就会失败。例如:
打印“分数”,尽管 (31/20)20 应等于 3,因为实际计算结果最终为 2.9999992847442626953125。
任何类似的方法,无论是
fmodf
还是其他方法,都受此约束。在执行复杂或易于舍入的计算的应用程序中,通常您想要做的是为构成“整数”的内容定义一些“容差”值(这通常适用于浮点相等比较)。我们通常将这种容差称为epsilon。例如,假设我们会原谅计算机最多 +/- 0.00001 的舍入误差。然后,如果我们正在测试z
,我们可以选择 0.00001 的 epsilon 并执行以下操作:您实际上不想在此处使用
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:The problem with this and other similar techniques (such as
ceilf
, casting tolong
, 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: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 testingz
, we can choose an epsilon of 0.00001 and do:You don't really want to use
ceilf
here because e.g.ceilf(1.0000001)
is 2 not 1, andceilf(-1.99999999)
is -1 not -2.You could use
rintf
in place ofroundf
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.
不要忘记
math.h
和libm
。Don't forget
math.h
andlibm
.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.
这涉及计算舍入。您根据需要设置 epsilon:
This deals with computational round-off. You set the epsilon as desired:
我不是 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.