浮点比较

sas*_*har 63 c c++ floating-point

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");
}
Run Code Online (Sandbox Code Playgroud)

我本来期望这段代码的输出0 are right.但令我沮丧的是输出是什么1 is right原因?

use*_*016 130

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");
}
Run Code Online (Sandbox Code Playgroud)

花车得到比较期间晋升为双打,由于彩车比双打不太精确,0.7为float是一样的0.7为双.在这种情况下,0.7当浮动变得低于0.7时,它被提升为双倍.正如克里斯蒂安所说,0.5是2的幂总是完全代表,所以测试按预期工作:0.5 < 0.5是假的.

所以要么:

  • 更改floatdouble,或者:
  • 更改.7.5.7f.5f,

你会得到预期的行为.

  • 假设IEEE 754浮点,行为是100%可预测的.`0.7`变成最接近的`double`(0.6999999999999999555910790149937383830547332763671875)并将其转换为`float`舍入到最近的`float`值(0.699999988079071044921875). (43认同)
  • +1这是唯一一个在看到问题时没有喊出"永不比较花车"的答案,并且实际上想到了这里真正发生的事情. (5认同)
  • @sasidhar:您应该假设所有浮点数都不会精确存储,而且会丢失一些信息.(因此浮点值的比较不应该精确地进行,而应该是误差范围).请注意,如果变量得到优化并且所有值在程序的持续时间内保留在寄存器中,那么您可能会得到不同的结果.尝试在发布模式下进行编译,优化器转到最高级别,看看结果是否发生变化. (4认同)
  • @sasidhar:0.7表示为浮动存储为"0.699999988079071044921875"并存储为双精度为"0.699999999999999955591079014994"因此存在"0.000000011920928910669204014994"的差异,在分配给"a"时丢失了该信息时无法重新创建信息`a`被转换为double. (3认同)

小智 15

问题是你要比较的常数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");
}
Run Code Online (Sandbox Code Playgroud)

输出:

0 are right

这等等问题对float和double比较最有效的方法涵盖了这个主题.

另外,这篇关于浮点数比较的天鹅座文章给出了一些提示:

设计了IEEE浮点数和双精度格式,以便数字按照"按字典顺序排列",用IEEE架构师William Kahan的话来说,"如果两个相同格式的浮点数被排序(比如x <y),那么当它们的位被重新解释为Sign-Magnitude整数时,它们的排序方式相同."

这意味着如果我们在内存中使用两个浮点数,将它们的位模式解释为整数,并进行比较,我们可以判断哪个更大,而不进行浮点比较.在C/C++语言中,此比较如下所示:

if (*(int*)&f1 < *(int*)&f2)
Run Code Online (Sandbox Code Playgroud)

这种迷人的语法意味着获取f1的地址,将其视为整数指针,并取消引用它.所有这些指针操作看起来都很昂贵,但它们基本上全部取消,只是意味着"将f1视为整数".由于我们将相同的语法应用于f2,因此整行意味着'比较f1和f2,使用它们的内存表示形式解释为整数而不是浮点数'.

  • 整数比较假定`sizeof(int)== sizeof(float)`.处理`double`时更糟糕的假设. (8认同)
  • 它也违反了严格别名规则. (2认同)