代码之家  ›  专栏  ›  技术社区  ›  Ashish

浮点与浮点文本比较时的奇怪输出

  •  33
  • Ashish  · 技术社区  · 16 年前
    float f = 0.7;
    if( f == 0.7 )
        printf("equal");
    else
        printf("not equal");
    

    为什么是输出 not equal ?

    为什么会发生这种情况?

    8 回复  |  直到 13 年前
        1
  •  53
  •   halfdan    14 年前

    这是因为在你的陈述中

      if(f == 0.7)
    

      if(f == 0.7f)
    

    但是正如Michael在下面的评论中所建议的,您永远不应该测试浮点值的精确相等性。

        2
  •  14
  •   Pascal Cuoq    12 年前

    甚至可以说,对于无法准确表示的文字浮点常量,应该有一个编译器警告,特别是当标准对于是否在运行时以设置为该时间的模式进行舍入或在编译时以另一种舍入模式进行舍入非常模糊时。

    所有可以精确表示的非整数都具有 5 5.

        3
  •  13
  •   Antti Haapala -- Слава Україні    6 年前


    3D CC CD
    根据IEEE 754标准,要将其转换为十进制,我们必须这样做:

    enter image description here


    这里的第一个数字是一个符号位。0表示(-1)^0表示我们的数字为正数。
    第二个8位是指数。二进制是01111011,十进制是123,但实际指数是123-127(总是127)= ,这意味着我们需要将得到的数字乘以2^(-4)。
    最后23个字节是有效位精度。第一位乘以1/(2^1)(0.5),第二位乘以1/(2^2)(0.25),依此类推。我们得到的是:


    enter image description here enter image description here

    我们需要把所有的数字(2的幂)加起来,再加上1(通常是1,以此类推)。它是

    现在让我们把这个数字乘以2^(-4),它来自指数。我们只是将上面的数字除以2四次:
    0,100000001490116119384765625
    我用MS计算器


    **
    我取0.1
    现在我将计算指数和有效位精度。逻辑乘以2个整数(0.1*2=0.2),如果大于1,则减去并继续。
    enter image description here
    数字是0.000110011,standart说在得到1之前我们必须向左移动。你怎么看我们需要4个班次,从这个数字开始计算 123 ). 现在的有效位精度是
    10011001100110011001100
    现在是整数。符号位 指数是123( 01111011 10011001100110011001100 这是一个整体
    让我们将其与上一章中的内容进行比较
    00111101110011001100110011001101
    正如你所看到的,最后一位是不相等的。这是因为我截断了数字。CPU和编译器知道后有效位精度不能保持,只需将最后一位设置为1。

        4
  •  2
  •   old_timer    7 年前

    int fun1 ( void )
    {
          float x=0.7;
          if(x==0.7) return(1);
          else       return(0);
    }
    int fun2 ( void )
    {
          float x=1.1;
          if(x==1.1) return(1);
          else       return(0);
    }
    int fun3 ( void )
    {
          float x=1.0;
          if(x==1.0) return(1);
          else       return(0);
    }
    int fun4 ( void )
    {
          float x=0.0;
          if(x==0.0) return(1);
          else       return(0);
    }
    int fun5 ( void )
    {
          float x=0.7;
          if(x==0.7f) return(1);
          else       return(0);
    }
    float fun10 ( void )
    {
        return(0.7);
    }
    double fun11 ( void )
    {
        return(0.7);
    }
    float fun12 ( void )
    {
        return(1.0);
    }
    double fun13 ( void )
    {
        return(1.0);
    }
    
    Disassembly of section .text:
    
    00000000 <fun1>:
       0:   e3a00000    mov r0, #0
       4:   e12fff1e    bx  lr
    
    00000008 <fun2>:
       8:   e3a00000    mov r0, #0
       c:   e12fff1e    bx  lr
    
    00000010 <fun3>:
      10:   e3a00001    mov r0, #1
      14:   e12fff1e    bx  lr
    
    00000018 <fun4>:
      18:   e3a00001    mov r0, #1
      1c:   e12fff1e    bx  lr
    
    00000020 <fun5>:
      20:   e3a00001    mov r0, #1
      24:   e12fff1e    bx  lr
    
    00000028 <fun10>:
      28:   e59f0000    ldr r0, [pc]    ; 30 <fun10+0x8>
      2c:   e12fff1e    bx  lr
      30:   3f333333    svccc   0x00333333
    
    00000034 <fun11>:
      34:   e28f1004    add r1, pc, #4
      38:   e8910003    ldm r1, {r0, r1}
      3c:   e12fff1e    bx  lr
      40:   66666666    strbtvs r6, [r6], -r6, ror #12
      44:   3fe66666    svccc   0x00e66666
    
    00000048 <fun12>:
      48:   e3a005fe    mov r0, #1065353216 ; 0x3f800000
      4c:   e12fff1e    bx  lr
    
    00000050 <fun13>:
      50:   e3a00000    mov r0, #0
      54:   e59f1000    ldr r1, [pc]    ; 5c <fun13+0xc>
      58:   e12fff1e    bx  lr
      5c:   3ff00000    svccc   0x00f00000  ; IMB
    

    这是关于语言的。该语言说0.7是双精度的,除非使用这种语法0.7f,否则它是单精度的。所以

      float x=0.7;
    

      if(x==0.7) return(1);
    

    00000028 <fun10>:
      28:   e59f0000    ldr r0, [pc]    ; 30 <fun10+0x8>
      2c:   e12fff1e    bx  lr
      30:   3f333333    svccc   0x00333333
    
    00000034 <fun11>:
      34:   e28f1004    add r1, pc, #4
      38:   e8910003    ldm r1, {r0, r1}
      3c:   e12fff1e    bx  lr
      40:   66666666    strbtvs r6, [r6], -r6, ror #12
      44:   3fe66666    svccc   0x00e66666
    

    单3f333333 双3FE666

    请参见eeeefffffffffffffffffffffffff

    双倍是

    请参见EEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

    00111111001100110011... single
    001111111110011001100110... double
    
    0 01111110 01100110011... single
    0 01111111110 01100110011... double
    

    就像10进制的1/3是0.3333。。。永远。我们这里有一个重复的模式0110

    01100110011001100110011 single, 23 bits
    01100110011001100110011001100110.... double 52 bits.
    

    这就是答案。

    如果(x==0.7)返回(1);
    

    将分数加倍是一种错误

    01100110011001100110011000000000....
    

    这不等于

    01100110011001100110011001100110...
    

      if(x==0.7f) return(1);
    

    这种提升不会发生,因为相同的位模式会相互比较。

    为什么1.0可以工作?

    00000048 <fun12>:
      48:   e3a005fe    mov r0, #1065353216 ; 0x3f800000
      4c:   e12fff1e    bx  lr
    
    00000050 <fun13>:
      50:   e3a00000    mov r0, #0
      54:   e59f1000    ldr r1, [pc]    ; 5c <fun13+0xc>
      58:   e12fff1e    bx  lr
      5c:   3ff00000    svccc   0x00f00000  ; IMB
    
    0011111110000000...
    0011111111110000000...
    
    0 01111111 0000000...
    0 01111111111 0000000...
    

    哈尔夫丹投票率最高且经过检查的答案是正确的答案,这是一种混合精度的情况,你永远不应该进行相等的比较。

    答案中没有说明原因。0.7使1.0无法工作。没有显示0.7失败的原因。重复的问题1.1也失败了。


    编辑

    在这里,我们可以从这个问题中取出来,这是一个已经得到回答的不同问题,但这是同一个问题,也有“什么……”的初始冲击。

    int fun1 ( void )
    {
          float x=0.7;
          if(x<0.7) return(1);
          else       return(0);
    }
    int fun2 ( void )
    {
          float x=0.6;
          if(x<0.6) return(1);
          else       return(0);
    }
    
    Disassembly of section .text:
    
    00000000 <fun1>:
       0:   e3a00001    mov r0, #1
       4:   e12fff1e    bx  lr
    
    00000008 <fun2>:
       8:   e3a00000    mov r0, #0
       c:   e12fff1e    bx  lr
    

    01100110011001100110011 single, 23 bits
    01100110011001100110011001100110.... double 52 bits.
    
    01100110011001100110011000000000....
    

    少于。

    01100110011001100110011001100110...
    

    但是,当从双精度转换为单精度时,或者在表示一般情况时 作为一个单一的IEEE 754。

    00110011001100110011001100110011.... double 52 bits.
    00110011001100110011001 is NOT the fraction for single
    00110011001100110011010 IS the fraction for single
    

    00110011001100110011010
    

    00110011001100110011010000000000....
    

    大于

    00110011001100110011001100110011....
    

    因此,不必讨论使用equals,问题仍然是0.7是双0.7f是单,如果它们不同,则运算将提升到最高精度。

        5
  •  1
  •   Kevin Mack    10 年前

    更好的做法是做如下事情

    float f = 0.7;
    if( fabs(f - 0.7) < FLT_EPSILON )
        printf("equal");
    else
        printf("not equal");
    

    由于舍入或初始化误差不太可能超过FLT_EPSILON的值,因此这将为您提供所需的可靠等效性测试。

        6
  •  1
  •   Jimmy Pettersson    9 年前

          // Floating point comparison:
    
            bool CheckFP32Equal(float referenceValue, float value)
            {
               const float fp32_epsilon = float(1E-7);
               float abs_diff = std::abs(referenceValue - value);
    
               // Both identical zero is a special case
               if( referenceValue==0.0f && value == 0.0f)
                  return true;
    
               float rel_diff = abs_diff / std::max(std::abs(referenceValue) , std::abs(value) ); 
    
               if(rel_diff < fp32_epsilon)
                     return true;
               else 
                     return false;
    
            }
    
        7
  •  0
  •   Setu Kumar Basak    10 年前

    考虑一下:

    int main()
    {
        float a = 0.7;
        if(0.7 > a)
            printf("Hi\n");
        else
            printf("Hello\n");
        return 0;
    }
    

    如果 (0.7>(a) 0.7 0.7 'Hi'

    例子:

    int main()
    {
        float a=0.7;
        printf("%.10f %.10f\n",0.7, a);
        return 0;
    }
    

    输出:

        8
  •  -2
  •   Muhammad Azam    7 年前

    如果更改的数据类型 F 双重的 ,它会打印出来 平等的 ,这是因为浮点中的常量存储在 双重的 并且不漂浮在水中 ,双精度高,浮点精度低,双值存储在 64 位二进制和浮点值存储在

    推荐文章