检查float是否为整数


71

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

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


8
当该数字大于最大允许整数值时,您的方法将失败。
Mark Ransom

请参阅我的答案以解决OP方法的问题。
R .. GitHub停止帮助ICE,

正确的答案肯定是:您问的是错误的问题。
约翰·马歇尔

@约翰·马歇尔:那么,正确的问题是什么?
sidyll 2011年

1
好吧,您正在尝试做什么?如果要在中存储值float,大概是因为要对其进行浮点运算。然后,您的问题就变成了:该变量的值在特定于领域的方式中是有点蓬松的,并且取决于您对算术的认真程度,因此它的值是蓬松积分的吗?要有意义地回答该问题,您需要考虑特定于域的蓬松度。或者,换一种说法:在哪种情况下,正确的方法是不以int适当的大小存储您的值?
约翰·马歇尔

Answers:


71

除了已经给出的好答案之外,您还可以使用ceilf(f) == ffloorf(f) == ftrue如果f是整数,则两个表达式均返回。它们还会返回falseNaN(NaN总是比较unqual)和true±无限,并且不会溢出用于保存截断结果的整数类型,因为floorf()/ ceilf()return floats。


1
好吧,这违背了目的。我想要的是检查浮点数是否为整数,如标题所示;而不是四舍五入。在后一种情况下,我总是有一个整数。但是也感谢您指出这一点。
sidyll 2011年

1
@sidyll:这两个表达式都是round f,是的,但是这样做是为了检查它是否是整数。
Marc Mutz-mmutz 2011年

@sidyll:更准确地说:请注意,与相比f,舍入运算的结果是怎样的,谢谢,我已经编辑了答案以使其更清楚。
Marc Mutz-mmutz 2011年

4
虽然这个作品,ceilf并且floorf都在至少某些archs(主要是X86)由于需要改变不必要的昂贵的操作和恢复舍入模式。更快的测试是rintf(f)==f。使用-fno-math-errno,GCC将编译rintf为单个内联指令。
R .. GitHub停止帮助ICE 2013年

4
@R ..我是否正确假设nearbyintf没有异常或标记也可以这样做?
斯利普·汤普森

24

请记住,这里的大多数技术都是有效的,前提是由于先前的计算导致的舍入误差不是一个因素。例如,您可以使用roundf,例如:

这种方法和其他类似技术(例如ceilf,强制转换为long等)的问题在于,尽管它们对于整数常数很有用,但是如果数字是经过浮点舍入运算的结果,则它们将失败。错误。例如:

即使(3 1/2020应该等于3 ,也会打印“分数”,因为实际的计算结果最终为2.9999992847442626953125

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

您实际上并不想在ceilf这里使用,因为egceilf(1.0000001)是2而不是1,并且ceilf(-1.99999999)是-1而不是-2。

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

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


9

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


我只是想知道,如果与我最初的解决方案相比(如果@R ..在另一个类似的答案中说),这是否不太昂贵。
sidyll 2011年

2
@mmutz:我说过应该戴眼镜吗?
sidyll 2011年

号码为23.9999999999时可以正常工作吗?在我看来,这仅适用于数字为24.0000000000001
乔纳森五世


5

1
如果sizeof(f) > sizeof(long)这可能不成立。
Mark Ransom

2
如果有人找到这个答案并尝试将它应用于某个答案,只是为了指出问题double
Mark Ransom

1
好点子。因为double我会使用long longLLONG_MAX/ LLONG_MIN
R .. GitHub停止帮助ICE,

3
@mangledorf:您的转换无效。(long)f如果该值不能表示为,则调用未定义的行为long。因此,为了安全起见,您必须先进行比较。
R .. GitHub停止帮助ICE 2014年

1
@EmileCormier:作为一个数字,-1.1 * 10 ^ 20还是一个整数,所以我想你的意思有所不同。但是,的精度float受到限制,以使得最接近该数字的可表示值是-109999998686059298816,它也是一个整数。由于float具有24位有效数,因此大小至少2 ^ 24的任何值在小数点之后都没有有效位。C要求long至少为32位,因此值大于LONG_MAX或小于LONG_MIN该范围之外的值。
R .. GitHub STOP HELPING ICE

0

我不确定100%,但是当您将f转换为int并从f中减去时,我相信它会转换为浮点数。在这种情况下这可能无关紧要,但是如果您出于某种原因希望它是一个int,则可能会带来一些问题。

我不知道它本身是否是一个更好的解决方案,但是例如,您可以使用模数数学: float f = 4.5886; bool isInt; isInt = (f % 1.0 != 0) ? false : true; 根据您的编译器,您可能需要或不需要1.之后的.0,这又使整个隐式强制转换起作用。在此代码中,如果小数点右边的全为零,则bool isInt应该为true,否则为false。


1
%操作仅适用于整数。您对int被强制转换回浮点数是正确的。
Mark Ransom

我的错误,我应该使用(fmod(f,1.0)!= 0)代替。
Controllerface

是的,我知道它将保持浮动状态,但我只想检查一下。
sidyll 2011年

不会在gcc上编译
weima 18'Sep

0

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.