在 Java 中使用双精度保持精度

2022-08-31 06:52:22
public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

上面的代码打印:

11.399999999999

我如何让它只打印(或能够用作)11.4?


答案 1

正如其他人所提到的,如果你想拥有 11.4 的精确表示形式,你可能希望使用 BigDecimal 类。

现在,稍微解释一下为什么会发生这种情况:

Java 中的和基元类型是浮点数,其中数字存储为分数和指数的二进制表示形式。floatdouble

更具体地说,双精度浮点值(如 type)是 64 位值,其中:double

  • 1 位表示符号(正数或负数)。
  • 指数为 11 位。
  • 52 位为有效数字(作为二进制的小数部分)。

这些部分组合在一起以生成值的表示形式。double

(来源:维基百科:双精度)

有关如何在 Java 中处理浮点值的详细说明,请参见 Java 语言规范的第 4.2.3 节:浮点类型、格式和值

、 、 类型是定点数,是数的精确表示。与定点数不同,浮点数有时(可以安全地假设“大多数时间”)无法返回数字的精确表示形式。这就是您最终导致 .bytecharintlong11.3999999999995.6 + 5.8

当需要精确的值(如 1.5 或 150.1005)时,您需要使用一种定点类型,该类型将能够精确地表示数字。

正如已经多次提到的,Java有一个BigDecimal类,它将处理非常大的数字和非常小的数字。

从该类的 Java API 参考中:BigDecimal

不可变的任意精度有符号十进制数。BigDecimal 由任意精度的未缩放整数值和 32 位整数刻度组成。如果为零或正,则小数位数为小数点右边的位数。如果为负,则数字的未缩放值乘以 10 的平数的幂。因此,由 BigDecimal 表示的数字值是 (未缩放值× 10^-scale)。

关于Stack Overflow有很多与浮点数及其精度有关的问题。以下是可能感兴趣的相关问题列表:

如果你真的想深入了解浮点数的细节,看看每个计算机科学家都应该知道的关于浮点算术的知识


答案 2

例如,当您输入双精度值时,您得到的值实际上是最接近的可表示双精度值,它正好是:33.33333333333333

33.3333333333333285963817615993320941925048828125

将其除以 100 得到:

0.333333333333333285963817615993320941925048828125

它也不能表示为双精度数字,因此它再次被舍入到最接近的可表示值,即:

0.3333333333333332593184650249895639717578887939453125

打印此值时,它会再次四舍五入到 17 位小数位,给出:

0.33333333333333326