相似的代码输出不同的结果

时间:2020-07-02 14:29:52

标签: c floating-point double

以下代码的输出为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; 
} 

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

7 个答案:

答案 0 :(得分:5)

此行:

x=(float)3.3==3.3;

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

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

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

答案 1 :(得分:2)

分配的值3.3double的类型,但是您试图将doublefloat进行比较(通过类型转换,因此,精度损失)。

3.3double的值是3.299999999999999822,而float中相同的值被测量为3.299999952F,这显然是不相等的。因此,如果您将其他3.3键入为float,则结果将为true(即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.5float中的double等于3.50000000 ...,因此,所有尾随零都从分配的变量中被截断,因此得到1.0000000。但这与3.3有点相反。

答案 2 :(得分:2)

float的精度低于double3.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.5 doublefloattrue之间的比较,它与the binary conversion有关,3.3受到考虑到link above中可以看到尾数转换将无限期地进行的事实,确切的值根本无法用doublefloat表示,而{{1} }可以完美地代表in doublefloat alike

答案 3 :(得分:1)

要查看float导致的精度损失:

#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

答案 4 :(得分:1)

3.3二进制是

11.0100110011001100110011001100110011001100110011

转换为float时,一些精度会被截断

11.0100110011001100110011001100110

转换回两倍后,计算机仅使用0

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

答案 5 :(得分:1)

3.3这样的值不能用有限数量的位精确地表示,就像1/3的结果不能精确地用有限数量的十进制数表示一样,因此您最终会存储一个近似值。

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

相反,3.5 可以精确地用floatdouble类型表示,因此比较(float) 3.5 == 3.5成功。

就像整数类型一样,浮点类型的有效位数是2的幂的和-值3.5表示为1.75 * 21,而二进制数表示有效位数{{ 1}}是1.75-1.1121 * 20 + 1 * 2-1 + 1 * 2-2

答案 6 :(得分:0)

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

所以问题在于

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

为假,因为将3.3强制转换为float会降低精度。相比之下,对于3.5,结果将是true,因为3.5可以精确地表示为float,而精度与double相同。

实际上,可以将情况与将值从较高的等级转换为较低的值,然后像下面的代码片段中返回那样进行比较:

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