【问题标题】:Similar codes output different results相似的代码输出不同的结果
【发布时间】:2020-07-02 14:29:52
【问题描述】:

以下代码的输出为0.0000000:

#include <stdio.h>

int main() {
    float x;
    x = (float)3.3 == 3.3;

    printf("%f", x);

    return 0;
}

而这段代码输出1.000000:

int main() { 
    float x; 
    x = (float)3.5 == 3.5; 

    printf("%f", x); 

    return 0; 
} 

这两个代码的唯一区别是比较中的值,但是结果不一样,这是为什么呢?

【问题讨论】:

  • 此代码输出为 1. int main(){ float x; x=(浮点数)3.5==3.5; printf("%f",x);返回0; } Ans 1.00 // 为什么这个输出是 1
  • 代码应该在问题中,而不是在 cmets 中。
  • 也许第二个3.3 是double,它有不同的位表示。
  • 3.3 的值不能用浮点数精确表示。当3.3 转换为float 时,会丢失一些精度。将结果与3.3(即double 常量)进行比较时,将其转换回double,但不会恢复丢失的精度,因此两个值比较不相等。
  • 请注意,(float)3.3==3.3 等价于 ((float)3.3)==3.3,这可能不是您想要的。比较的结果是一个整数,在赋值时会隐式转换为float。这与(float)(3.3==3.3) 完全不同。

标签: c floating-point double


【解决方案1】:

这一行:

x=(float)3.3==3.3;

比较(float)3.3 和3.3 是否相等并将结果分配给x。由于强制转换,比较左侧的类型为 float,而右侧的类型为 double,这是浮点常量的默认类型。

值 3.3 不能用二进制浮点数精确表示,因此存储的实际值是一个近似值。由于类型 float 和 double 的精度不同,这个近似值会有所不同,因此相等性将被评估为 false,即 0。这是分配给 x 的值。

关于您在检查的数字是 3.5 时为什么 x 是 1 的评论,那是因为 3.5 可以以二进制精确表示,并且两种类型都具有存储它的精度值,所以它们比较相等。

【讨论】:

    【解决方案2】:

    分配的值 3.3 是 double 的一种类型,但您正尝试将 double 与 float 进行比较(通过类型转换,因此精度损失)。

    3.3 与 double 的值是 3.299999999999999822,而 float 中的相同值测量为 3.299999952F,这显然是不相等的。因此,如果您将另一个 3.3 类型转换为 float,结果将为真(即 1.0000000)。

    而不是:

    x = (float) 3.3 == 3.3; // float != double precision (precision loss)
    

    如果你这样做:

    x = (float) 3.3 == (float) 3.3; // converting both to make precision equal
    

    或者,

    x = (double) 3.3 == (double) 3.3; // converting . . . (same)
    

    换句话说,如果您将任何一个表达式转换为与另一个相同,则比较将相等。

    另外,请注意3.5 在float 和double 中都等于3.50000000...,因此所有尾随零都从分配的变量中截断,因此您得到1.0000000。不过这玩意跟3.3有点相反。

    【讨论】:

      【解决方案3】:

      float 的精度低于double,3.3 常量的值默认为 double 并且为 3.299999999999999822,转换为 float is 3.29999995231628418 时相同的常量。

      3.299999999999999822 == 3.29999995231628418 这个比较的结果是false 即0。

      给定优先级规则,表达式为x = ((float)3.5 == 3.5);,先进行比较,然后将结果赋值给x。

      当没有强制转换时,两个常量都默认为double,因此它们之间的比较结果自然是true,即1。

      关于3.5double和float之间的比较true,它与the binary conversion有关,3.3是一个近似值,因为尾数转换将无限期地进行正如在link above 中所见,确切的值根本无法在double 和float 中表示,而3.5 完全可以在in double 和float alike 中表示。

      【讨论】:

        【解决方案4】:

        查看浮点精度损失:

        #include <stdio.h>
        int main(){
            float x = 3.3;
            double d = 3.3;
            printf("%12.9f %12.9lf\n",x, d);
        

        输出:

         3.299999952  3.300000000
        

        【讨论】:

          【解决方案5】:

          3.3 二进制是

          11.0100110011001100110011001100110011001100110011
          

          当转换为float 时,某些位的精度会被截断

          11.0100110011001100110011001100110
          

          当转换回双精度时,计算机只使用0's

          11.0100110011001100110011001100110000000000000000
          

          所以

          3.3                     11.0100110011001100110011001100110011001100110011
          (float)3.3              11.0100110011001100110011001100110
          (double)((float)3.3)    11.0100110011001100110011001100110000000000000000
          

          3.5 比较

          3.5                     11.1000000000000000000000000000000000000000000000
          (float)3.5              11.1000000000000000000000000000000
          (double)((float)3.5)    11.1000000000000000000000000000000000000000000000
          

          【讨论】:

            【解决方案6】:

            像3.3 这样的值不能准确地用有限的位数表示,就像1/3 的结果不能用有限的十进制数字准确表示一样,所以你结束了存储该值的近似值。

            float 近似值与 double 近似值不同,因此比较 (float) 3.3 == 3.3 失败。

            相比之下,3.5 可以在float 和double 类型中精确表示,因此(float) 3.5 == 3.5 比较成功。

            就像整数类型一样,浮点类型的有效数字是 2 的幂 - 值 3.5 表示为 1.75 * 2<sup>1</sup>,有效数字 1.75 的二进制表示形式为 @987654333 @ - 1 * 2<sup>0</sup> + 1 * 2<sup>-1</sup> + 1 * 2<sup>-2</sup>,或 1 + 0.5 + 0.25。

            【讨论】:

              【解决方案7】:

              问题是在将值3.3(double 类型的文字)转换为具有强制类型转换(float)3.3 的浮点值时,您会失去精度。这种精度损失是不可逆的,即使比较运算符 == 会将左操作数提升回双精度类型。

              问题是这样的

              (double)((float)3.3) == (double)3.3
              

              将是错误的,因为 3.3 到 float 的转换失去了精度。相反,对于3.5,结果将是true,因为3.5 可以精确地表示为float,其精度与double 相同。

              实际上,这种情况可以比作将一个值从较高的等级转换为较低的等级,然后再返回,如下面的 sn-p:

              unsigned int x = 257;
              unsigned char y = x;
              unsigned int x2 = y;
              printf("%d\n", x==x2);   // 0
              
              x = 255;
              y = x;
              x2 = y;
              printf("%d\n", x==x2);   // 1
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-04-22
                • 1970-01-01
                • 2017-05-21
                • 2021-08-23
                • 2016-08-02
                相关资源
                最近更新 更多