9

在看到以下代码片段的结果后,我对浮点数的行为感到困惑。

    float var1 = 5.4f;
    float var2 = 5.5f;

    if(var1 == 5.4)
        System.out.println("Matched");
    else
        System.out.println("Oops!!");

    if(var2 == 5.5)
        System.out.println("Matched");
    else
        System.out.println("Oops!!");

输出:

Oops!!
Matched

这是因为十进制数不能完全以基数 2 二进制格式表示吗?或者这是因为我将浮点类型变量与双精度类型进行比较时的精度?如果是,那么为什么它适用于下一个变量?

4

5 回答 5

16

这是因为十进制数不能完全以基数 2 二进制格式表示吗?

是的。基本上,5.4f并不5.4d相同,因为它们都不是 5.4 的精确表示

5.5f并且5.5d 相同的,因为它们都是 5.5 的精确表示。

请注意,这与- 浮点文字的默认类型5.4隐含相同。任何使用操作数为and的二元运算符都会将 a 提升为 a并对两个值执行操作。5.4ddoublefloatdoublefloatdoubledouble

就十进制类型而言,它可能会使事情更容易考虑。假设我们有两种类型,Decimal5 和 Decimal10,它们是具有 5 位或 10 位有效数字的十进制数。然后考虑“三分之一”和“四分之一”:

A third:
Decimal5:  0.33333
Decimal10: 0.3333333333

A quarter (showing trailing zeroes just for clarity):
Decimal5:  0.25000
Decimal10: 0.2500000000

将最接近三分之一的 Decimal5 值与 Decimal10 值进行比较时,Decimal5 值将转换为 Decimal10 值 0.3333300000,它不等于 0.3333333333。这类似于您的第一个示例。

但是,在比较一个季度的值时,Decimal5 值 0.25000 转换为 0.2500000000,这与我们对一个季度的 Decimal10 值相同。这类似于您的第二个示例。

当然,二进制浮点类型比这要复杂一些,包括归一化、次正规数等——但就您的示例而言,这个类比已经足够接近了。

于 2013-09-19T06:55:47.970 回答
6

不同之处在于 5.5 可以在floatdouble- 中精确表示,而 5.4 不能精确表示。
参考http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

于 2013-09-19T06:57:20.903 回答
3

将您的 if 条件替换为:

if(var1 == 5.4f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

if(var2 == 5.5f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

然后它会打印Matched两次。原因是因为f最终没有限定符,Java 将5.4其视为 double 5.5.

于 2013-09-19T06:55:55.223 回答
2

很容易看出:

if(var1 == 5.4f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

if(var2 == 5.5f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

输出:

Matched
Matched

5.4f和的二进制表示5.4d不完全相同

于 2013-09-19T06:56:30.673 回答
0

如果要比较浮点类型,则必须使用与 epsilon 进行比较。在这里,您可以看到可用于比较浮点类型的所有方法。

于 2013-09-19T07:02:50.500 回答