0Pricing
Java Academy · 课时

为什么不应使用 double 表示金额

浮点数精度问题

为什么不应使用 double 表示金额 是 CoddyKit 上的免费 Java Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

危险的默认选择

将价格存储在 double 中似乎很自然。遗憾的是,double 无法精确表示大多数十进制小数,这会产生细微误差,破坏财务计算。

经典意外

使用 double 将 0.1 和 0.2 相加,得到的并不是 0.3,而是一个带有微小舍入误差的值。

public class Main {
    public static void main(String[] args) {
        double result = 0.1 + 0.2;
        System.out.println(result);
    }
}

原因

计算机以二进制存储 double。正如三分之一无法用十进制精确表示一样,许多小数(例如 0.1)也无法用二进制精确表示。

计算机会存储最接近的二进制近似值,而误差会不断累积。

误差不断累积

单个微小误差可能看起来无伤大雅,但在遍历数千笔交易的循环中,这些差异会累积成明显的错误。

public class Main {
    public static void main(String[] args) {
        double total = 0.0;
        for (int i = 0; i < 10; i++) {
            total += 0.1;
        }
        System.out.println(total);
    }
}

相等比较失败

由于舍入误差,使用 == 比较计算得到的双精度浮点数时,如果您预期它们相等,比较结果往往会失败。

public class Main {
    public static void main(String[] args) {
        double a = 0.1 + 0.2;
        double b = 0.3;
        System.out.println(a == b);
    }
}

金额必须精确

在金融领域,哪怕只有几分之一美分的误差也是不可接受的。审计人员希望总额精确到每一分钱。

因此,绝不能使用浮点类型存储金额。

解决方案:BigDecimal

Java 提供了 BigDecimal,这是一个能够精确存储十进制数的类。它分别记录未缩放值和 scale,因此 0.1 真正表示的就是 0.1。

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.1");
        BigDecimal b = new BigDecimal("0.2");
        System.out.println(a.add(b));
    }
}

始终使用字符串构造方式

请从字符串而不是 double 创建 BigDecimal。传入 double 会将二进制误差带入 BigDecimal。

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal fromDouble = new BigDecimal(0.1);
        BigDecimal fromString = new BigDecimal("0.1");
        System.out.println(fromDouble);
        System.out.println(fromString);
    }
}

或者使用 valueOf

BigDecimal.valueOf 是一种安全的快捷方式。它使用 double 的规范字符串形式进行转换,从而避免原始二进制误差。

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal price = BigDecimal.valueOf(19.99);
        System.out.println(price);
    }
}

将金额按分存储

对于简单情况,另一种选择是使用 long 将金额存储为整数分数。这样,19.99 美元就变成 1999 分,所有运算都是精确的整数运算。

public class Main {
    public static void main(String[] args) {
        long cents = 1999;
        long total = cents * 3;
        System.out.println(total + " cents");
    }
}

要点

在科学和图形处理等允许小误差的场景中,请使用 float 和 double。对于金额以及任何必须精确的值,请使用 BigDecimal 或整数分。

快速检查

测试您对浮点数 precision 的理解。

回顾

您已经了解 double 为什么不适合金额:

  • 二进制浮点数无法精确存储许多十进制小数
  • 像 0.1 + 0.2 不等于 0.3 这样的误差会不断累积
  • 使用 BigDecimal 进行精确的十进制运算
  • 从字符串或使用 valueOf 创建它,绝不要直接从原始 double 创建
  • 存储整数分是另一种精确的选择

常见问题解答

「为什么不应使用 double 表示金额」课时是免费的吗?

是的 — 「为什么不应使用 double 表示金额」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「为什么不应使用 double 表示金额」这节课中我会学到什么?

浮点数精度问题 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「为什么不应使用 double 表示金额」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 为什么不应使用 double 表示金额
  2. 使用 BigDecimal
  3. 舍入与刻度
  4. 使用 BigInteger 处理超大数字
← 返回 Java Academy