在C中,int和float之间的关系比较是否可以直接进行?

我正在使用Visual Studio 6和一些用c编写的旧时代码。 我发现代码看起来像这样的问题..

int x = 3; float y = 3.0; if(x == y){ do some crazy stuff } 

这是一个有效的比较吗? 是否有可能在运行时浮点数的分配是3.0000001,这会失败?

好吧,我想你不会太鄙视听到比较花车的平等是一个新手的错误。

问题是许多小于整数值的增量实际上不能在IEEE浮点中精确表示。 因此,如果您通过尝试将其“索引”到3.0的值(以增量0.1为单位)到达浮点数,则很可能您的相等比较永远不会成立。

从类型强度的角度来看,这也是一个坏主意。 你应该将float转换为int,检查你的int是否“足够接近”(例如<3.1和> 2.9或者某些),或者更好的是如果你试图让那个浮点数对于类似计数器的东西做双重任务,避免整个想法。

这通常(即总是)是个坏主意。 如您所料,从3到3.0000001的比较确实会失败。

大多数人所做的,如果真的需要进行int-float比较,那就选择一些容忍度阈值并按照这样做,如下:

 int x = 3; float y = 3.0; // some code here float difference = (float) x - y; float tolerableDifference = 0.001; if ((-tolerableDifference <= difference) && (difference <= tolerableDifference)) { // more code } 

我将在这里逆势而上。 关于比较是否有效的第一个问题,答案是肯定的。 这完全有效。 如果您想知道浮点值是否恰好等于3,那么与整数的比较就可以了。 整数隐式转换为浮点值以进行比较。 实际上,以下代码(至少使用我使用的编译器)生成了相同的汇编指令。

 if ( 3 == f ) printf( "equal\n" ); 

 if ( 3.0 == f ) printf( "equal\n" ); 

所以这取决于逻辑和预期目标是什么。 语法没有任何内在错误。

还没有其他人引用它,我暂时还没有把它联系起来,所以这里有关于浮点表示和算术可怕边缘的经典论文: 每个计算机科学家应该知道浮点数 。

对于非数学家来说,这篇论文是一本具有挑战性的读物,但关键点在大量数学支持之间得到充分说明。

对于此讨论,此处其他答案所提出的要点均有效。 浮点运算是不精确的,因此对于精确相等的比较通常是一个坏主意。 因此,epsilon是你的朋友。

精确比较规则的一个例外是完全为零的测试。 在分割或对数之前测试恰好为零是完全合法的并且通常是明智的,因为对于任何非零值都很好地定义了答案。 当然,在存在IEEE规则和NaN的情况下,您可以稍后滑动并测试NaN或Inf。

对于您的具体示例,将执行“做一些疯狂的事情”。 3.0在运行时不会是3.0000001。

其他答案更多适用于一般情况,但即使是硬编码的epsilon也不是世界上最好的主意。 基于所涉及的实际数字的动态epsilon要好得多,因为数字越正,负数越多,硬编码的epsilon相关的可能性就越小。

不,你的用例没有问题,因为整数被精确映射到浮点数(没有十进制截断问题,例如0.3;但3是二进制科学计数法中的1.1E10 )。

在我可以想到的最糟糕的情况下,可能存在无法用float表示的整数,因为在两个连续的浮点数之间存在大于1的“间隙”,但即使在这种情况下,当整数被转换为浮点数时进行比较时,它将被截断为最接近的float,与float literal的方式相同。

因此,只要您的浮点数来自非十进制文字,与等效整数的比较将是相同的,因为在完成比较之前,整数将被转换为完全相同的浮点数。

问题的关键在于,在基数10,十进制中具有有限表示的浮点数并不总是在基数2,二进制中具有有限表示。

如果代码看起来像你发布的那样(没有干预计算),那么问题是3.0(float)3 (因为整数自动转换为浮点数)是相同的。 我认为在这种情况下保证它们是相同的,因为3可以完全表示为float

旁白:即使整数不能完全表示为float(即如果它真的很大),我想在大多数实现中, x.0(float)x都是相同的,因为编译器将如何生成x.0首先,如果不做(float)x事情? 但是,我想这不是标准所保证的。

您可能对游戏开发者大会讲座几何计算的数值稳健性感兴趣(又名EPSILON不是0.00001!) 。 它详细说明了为各种任务选择好的阈值/ epsilon值。

(在另一个答案中,提到“每个计算机科学家应该知道的浮点数”的+1也是如此。)

那太可怕了。 (我想知道你还能找到什么。)

x将被提升为浮动,但这对你没有帮助。 由于浮点数的表示方式,使用==来比较它们是不可靠的。

我可能建议这样的事情(检查绝对错误/差异):

 #define EPSILON 0.0001 if (fabs((float)x - y) < EPSILON) { /* Do stuff. */ } 

这是一种常见的方法,如果您的x和y值“很好”,可能就足够了。 如果你真的想深入探讨比较浮点数的话题,那么本文可能包含的信息比你想要的多。 它确实说到了epsilon方法:

如果已知expectedResult的范围,那么检查绝对错误是简单而有效的。 只需确保您的绝对误差值大于您正在处理的浮点范围和类型的最小可表示差异。

编辑

正确的方法是使用epsilon方法:

 #include  int x = 3; int y = 3.0; if (fabs((float) x - y) < 0.0001) { // Adjust the epsilon // Do stuff }