天天看点

C语言中float值的比较

    预测以下C程序的输出:

#include<stdio.h>
int main()
{
	float x = 0.1;
	if (x == 0.1)
		printf("IF");
	else if (x == 0.1f)
		printf("ELSE IF");
	else
		printf("ELSE");
}
           

    上面程序的输出是“ ELSE IF”,这意味着表达式“ x == 0.1”返回false,表达式“ x == 0.1f”返回true。

    让我们考虑以下程序,以理解上述输出背后的原因。

#include<stdio.h>
int main()
{
float x = 0.1;
printf("%d %d %d", sizeof(x), sizeof(0.1), sizeof(0.1f));
return 0;
}
           
在C编译器上,上述程序的输出为“ 4 8 4”。
它实际打印出float的大小,double的大小和float的大小。
           

    表达式中使用的值被视为double(双精度浮点格式),除非在末尾指定了“f”。所以表达式“x==0.1”的右边有一个double,左边是以单精度浮点格式存储的float。在这种情况下,float被提升为double。双精度格式比单精度格式使用更多的精度位。

    0.1 10 _{10} 10​(十进制的数0.1)的二进制等价数可以写成(0.0001100110011…) 2 _2 2​,它可以无限大(有关转换的更多信息,请参阅本文)。由于float的精度小于double,因此在某个点(float中为23,double中为52)之后,它将截断结果。因此,在将float提升为double(在比较时)之后,编译器将用零填充剩余的位。因此,我们得到的结果不同,两者的十进制当量也不同。

float值为
=> (0.1) (十进制)= (0.00011001100110011001100)(二进制)
float提升为double后,double值为:
=> (0.1)(十进制) = (0.00011001100110011001100000000000000000...)(二进制)
                                             ^ padding zeroes here
未提升的原始double值为:
=> (0.1)(十进制) = (0.0001100110011001100110011001100110011001100110011001)(二进制)

因此,我们可以看到两个方程的结果是不同的。
因此,“if”语句永远不能执行。
           

    请注意,当值(如0.1)使用的精度位多于单精度位时,将float提升为double只会导致不匹配。

    示例,下面的C程序打印“IF”。

#include<stdio.h>
int main()
{
	float x = 0.5;
	if (x == 0.5)
		printf("IF");
	else if (x == 0.5f)
		printf("ELSE IF");
	else
		printf("ELSE");
}
           

    输出:

IF
           

    这里0.5 10 _{10} 10​的二进制等价物是(0.100000…) 2 _2 2​(浮点型和双精度型都不会丢失精度)。因此,如果编译器在升级时填充额外的零,那么我们将得到相同的结果,在比较中,左右两侧的十进制等价值(x==0.5)。

参考文档

[1]Abhay Rathi.Comparison of a float with a value in C[EB/OL].https://www.geeksforgeeks.org/comparison-float-value-c/,2020-11-17.