int main()
{
float a = 0.7;
float b = 0.5;
if (a < 0.7)
{
if (b < 0.5) printf("2 are right");
else printf("1 is right");
}
else printf("0 are right");
}
我希望这段代码的输出是
0 are right
。但令我沮丧的是,为什么是
1 is right
?#1 楼
int main()
{
float a = 0.7, b = 0.5; // These are FLOATS
if(a < .7) // This is a DOUBLE
{
if(b < .5) // This is a DOUBLE
printf("2 are right");
else
printf("1 is right");
}
else
printf("0 are right");
}
比较期间,浮点数被提升为两倍,并且由于浮点数的精度低于两倍,因此0.7的浮点数与0.7的两倍不相等。在这种情况下,当浮点数升为0.7时,其效果将不及两倍。正如克里斯蒂安所说,0.5始终是2的幂,因此该测试按预期工作:
0.5 < 0.5
是错误的。所以,要么:
将
float
更改为double
,或:将
.7
和.5
更改为.7f
和.5f
,,您将获得预期的行为。
评论
第一个if和第二个if应该以相同的方式评估吗?所以答案应该是2对或0对,但是为什么1对呢?
– sasidhar
2011年8月10日13:08
+1对于在看到问题并真正思考这里到底发生了什么的情况下,没有指出“从不比较浮点数”的唯一答案。
–克里斯蒂安·劳(Christian Rau)
2011年8月10日13:13
假定IEEE 754浮点,该行为是100%可预测的。 0.7成为最接近的双精度数(0.6999999999999999555910790149937383830547332763671875),并将其转换为浮点舍入到最接近的浮点值(0.699999988079071044921875)。
–R .. GitHub停止帮助ICE
2011年8月10日下午14:28
@sasidhar:表示为float的0.7存储为0.699999988079079071044921875,存储为双精度值的是0.699999999999999955555579079014994,所以存在0.000000011920928910669204204014994的差值0.000000011920928910669204014994,该差值在将a转换为double值时无法重新创建。
–马丁·约克
2011年8月10日16:10
@sasidhar:您应该假定不会精确存储所有浮点数,并且它们会丢失一些信息。 (因此,不应精确地比较浮点值,而应在误差范围内进行比较)。请注意,如果变量已优化,并且在程序执行期间所有值都保留在寄存器中,则可能会得到不同的结果。尝试在发布器模式下将优化器设置为最高级别,然后查看结果是否更改。
–马丁·约克
2011年8月10日16:15
#2 楼
问题是要比较的常数是double
而不是float
。同样,将常数更改为易于表示的值(例如5
)将使它表示为0 is right
。例如,main()
{
float a=0.25,b=0.5;
if(a<.25)
{
if(b<.5)
printf("2 are right");
else
printf("1 is right");
}
else
printf("0 are right");
}
输出:
0 are right
关于最有效的浮点和双精度方式的SO问题比较涵盖了该主题。
此外,cygnus上有关浮点数比较的这篇文章为我们提供了一些技巧:
IEEE float和double格式的设计目的是数字
是按字典顺序排序的,用IEEE
建筑师威廉·卡汉(William Kahan)的话,意思是“如果两个
相同格式的浮点数被排序(例如x
这意味着如果我们在内存中采用两个浮点数,则对其位进行解释
模式为整数,并进行比较,我们可以知道哪个更大,而无需进行浮点比较。在C / C ++语言中,此
比较看起来像这样:
if (*(int*)&f1 < *(int*)&f2)
这种迷人的语法意味着采用f1的地址,将其视为
整数指针,然后取消引用。所有这些指针操作看起来都很昂贵,但它们基本上都被抵消了,只是意味着“将f1
作为整数”。由于我们对f2采用相同的语法,因此整行
表示“比较f1和f2,使用它们在内存中的表示形式
解释为整数而不是浮点数”。
评论
整数比较假定sizeof(int)== sizeof(float)。处理双精度时的假设甚至更糟。
–赞·山猫
2011年8月10日16:10
它还违反了严格的别名规则。
–osgx
2011年8月11日,下午5:09
#3 楼
这是由于从float转换为double时的舍入问题#4 楼
通常,将相等与浮点数进行比较是一项危险的工作(实际上,这是您在>的边界上进行比较时所做的事情),请记住,以十进制表示的某些分数(例如1/3)不能完全相同地表示可以说是二进制,0.5= 0.1
,在float或double中将是相同的。0.7=0.10110011001100
永远如此,不能完全用二进制表示0.7,会出现舍入错误,并且浮点数和双精度数之间可能(非常非常细微)不同。请注意,在浮点数和双精度数之间切换会截取不同的小数位数,因此结果不一致。
评论
您应该阅读“每位计算机科学家都应了解的浮点算术知识”。0.7不是浮点数,而是两倍。这可能是该行为的原因
原因之一是a是浮点数,.7是双精度数。
米奇,如果0.7 == 0.7,答案将是0,对吧
好点子。晚了。我现在应该停止!.....