Java 减去两个十进制数得到奇怪的输出

Java 减去两个十进制数得到奇怪的输出,java,floating-point,Java,Floating Point,当我在玩Java拼图游戏时(我没有这本书),我偶然发现了这段代码 public static void main(String args[]) { System.out.println(2.00 - 1.10); } 输出为 public static void main(String args[]) { System.out.println(2.00 - 1.10); } 0.8999999999999999 当我尝试将代码更改为 publ

当我在玩Java拼图游戏时(我没有这本书),我偶然发现了这段代码

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
输出为

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
0.8999999999999999
当我尝试将代码更改为

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
2.00d-1.10d
我仍然得到与
0.8999999999999

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
对于,
2.00d-1.10f
输出为
0.899997961581421

对于,
2.00f-1.10d
输出为
0.89999999999

对于,
2.00f-1.10f
输出为
0.9

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }

为什么我不能首先将输出设置为
0.9
?我对这件事一无所知?有人能清楚地表达这一点吗?

因为在Java中,双值是

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
周围的工作可能是使用

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
不可变、任意精度有符号十进制数。大小数 由一个任意精度的整数无标度值和一个32位 整数刻度。如果为零或正,则刻度为位数 在小数点的右边。如果为负值,则为的未标度值 这个数字乘以10,等于 规模BigDecimal表示的数字的值为 因此(无标度值×10^-标度)

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
在旁注中您可能还需要检查大多数系统中浮点数的存储方式

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }

对浮点数执行的操作越多,舍入误差就越大。二进制0.1中的为0.00011001

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
因此,它不能用二进制精确表示。根据四舍五入(浮动或双精度)的不同位置,您会得到不同的答案

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
So 0.1f=0.00011001100 和0.1d=0.00011001

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
您注意到该数字在1100个周期内重复。但是,浮点和双精度在循环中的不同点将其拆分。因此,一个错误向上舍入,另一个向下舍入;导致差异

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
但最重要的是;
永远不要假设浮点数是精确的

其他答案是正确的,只需指向一个有效的引用,我引用:

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }
double:double数据类型是双精度64位IEEE 754 浮点数。其值的范围超出了本文的范围 讨论,但在浮点类型、格式和 Java语言规范的值部分。对于十进制值, 此数据类型通常是默认选择。如上所述, 此数据类型不应用于精确值,例如 货币

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }

尝试用二进制表示0.1;读“永远不要相信浮点数是精确的”是不可能的。正确的建议是理解浮点运算,并谨慎使用和设计。IEEE 754标准对浮点运算有很好的规定,只要有适当的知识和谨慎,浮点运算可以用于精确计算。@Eric我想看一个(非人为的)例子,说明假设浮点数是精确的是明智的?@Eric和while“阅读文档”总是很好的建议,它几乎从未被遵循。例如,在函数中,许多操作都是精确的,对于精确的某个定义,所有操作都是“精确的”,并且应该明智地假设它们分别是精确的和精确的,以便算法工作。@Pascal我编辑了我的答案,因为erics发表了意见,但我站在后面永远不要假设浮点数是精确的。BigDecimal不是一个包罗万象的解决方案。它没有提供正确的答案来计算给定年利率的月利息,转换货币,或计算三对一价格交易的单价。@EricPostPhischil:-是的,我知道你想说什么。我刚刚试着让OP意识到这有一些解决办法。这就是我写“解决办法可能是”的原因。我读了一篇有趣的文章:您引用的Oracle文档不正确。浮点运算由IEEE 754标准明确规定,在具备适当知识和谨慎的情况下,可用于精确计算。注意适当和谨慎地详细说明术语
?阅读IEEE 754标准和文本,如,和/或参加数值分析课程。在编写软件时,使用这些知识来评估可能发生的错误的界限和/或了解如何避免这些错误造成的问题(例如,编写容忍这些错误的软件,甚至利用这些错误的软件)。这样做是不准确的,你只是声称程序员可以处理这个负担。如果软件是用于任何重要用途的,程序员不应该编写超出他们能力范围的软件。