2016-01-20 82 views
0

我刚刚经历过的错误,其中两个号码都被比较,我发现以下有趣:double和float值比较

assert 1 == 1;//true   
    assert 1d == 1;//true   
    assert 1 == 1f;//true   
    assert 1d == 1f;//true 
    assert 1.1 == 1.1;//true   
    assert 1.1d == 1.1;//true   
    assert 1.1 == 1.1f;//false   
    assert 1.1d == 1.1f;//false 

我的问题是:为什么只有最后两个语句是假的?

+0

很好的解释:https://randomascii.wordpress.com/2012/06/26/doubles-are-not-floats-所以不要比较他们/ –

+1

你必须阅读[每个计算机科学家应该知道什么关于浮点运算](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) 。这是这个规范的资源。 –

+0

检查两种不同类型值的平等点有什么意义......没关系。 – haifzhan

回答

13

这是因为四舍五入。

1可以完全表示为double或float,因此前4个比较按预期工作。

1.1 == 1.1比较双重自身并按预期工作。

1.1d == 1.1与上述完全相同(d暗示在1.1中)。

最后两个比较比较1.1双精度到1.1浮点数。除1.1不能完全表示为float(或double),所以它会四舍五入到最接近的float(或double) - 但double有一个“higher resolution”,所以它们不会被类似地舍入。

,看看具体的值:

System.out.println(new BigDecimal(1.1f)); //1.10000002384185791015625 
System.out.println(new BigDecimal(1.1d)); //1.100000000000000088817841970012523233890533447265625 

正如意见建议的@yshavit,当你比较双到浮,浮被转换为双(due to numeric promotion),所以你真的比较两个双打:

System.out.println(new BigDecimal((double) 1.1f)); //1.10000002384185791015625 
System.out.println(new BigDecimal(1.1d)); //1.100000000000000088817841970012523233890533447265625 
+1

我想为奖励积分,'System.out.println(新的BigDecimal((双)1.1f))',以显示如何将四舍五入的浮点数扩大到一倍。 – yshavit

1

数字1.1不能完全用二进制浮点表示,因此在4字节浮动和8字节略有不同双重代表。

因此,最后两个是错误的,因为它们将一个double与一个浮点数比较,这个数字不能完全代表表示。
另一只比较双具有双或使用可以精确表示像1.0

+0

然后解释“assert 1d == 1f; // true” – logger

+0

阅读我更新的答案1.1 cannor可以表示 – AlexWien

2

启动此程序的值

public static void main(String... args) { 
    System.out.println("1.1f bits: " + Long.toBinaryString(Double.doubleToLongBits(1.1f))); 
    System.out.println("1.1d bits: " + Long.toBinaryString(Double.doubleToLongBits(1.1d))); 
} 

它yelds

1.1f as double: 11111111110001100110011001100110100000000000000000000000000000 
1.1d as double: 11111111110001100110011001100110011001100110011001100110011010 

这样做的原因行为是字面1.1,即小数部分1.1 dec不具有作为二进制小数的有限表示,并且IEEE-754存储器es数字作为二进制分数。所以它是四舍五入的,结果取决于转换时可用的位数(顺便说一句,转换甚至不会在运行时发生 - 这是编译器的工作)。

当比较不同规模的运营商时,推荐较小的运营商。请注意,这并不是说double和float不能相等的情况下:

3.1f != 3.1d 
3.0f == 3.0d