【问题标题】:Java more precision in arithmeticJava的算术精度更高
【发布时间】:2026-01-13 09:10:02
【问题描述】:

我正在用 Java 构建一个 Web 应用程序,它会进行数学运算并向用户显示步骤。在使用小数进行基本算术运算时,我经常会在准确的输出中弄得一团糟。

这是我的问题:

double a = 0.15;
double b = 0.01;
System.out.println(a - b);
// outputs 0.13999999999999999

float a = 0.15;
float b = 0.01;
System.out.println(a - b);
// outputs 0.14

float a = 0.16f;
float b = 0.01f;
System.out.println(a - b);
// outputs 0.14999999

double a = 0.16;
double b = 0.01;
System.out.println(a - b);
// outputs 0.15

对于complete 的准确性,两者都不可靠。有没有更精确的数字类,还是我应该将值四舍五入?

【问题讨论】:

标签: java math floating-accuracy


【解决方案1】:

BigDecimal怎么样?

尽管如此(例如 1/3),但并非对所有分区都完全准确。为此,您需要分数,它不是 JDK 的一部分,而是 easy to implement,例如两个整数(或 BigIntegers)。

【讨论】:

    【解决方案2】:

    您可以为此使用BigDecimal。这很丑,但它有效:

    BigDecimal a = new BigDecimal("0.15");
    BigDecimal b = new BigDecimal("0.01");
    System.out.println(a.subtract(b));
    

    请务必使用 String 参数或 valueOf 方法构造它们,如下所示:

    BigDecimal x = new BigDecimal("0.15");   // This is ok
    BigDecimal x = BigDecimal.valueOf(0.15); // This is also ok
    

    而不是双参数,像这样:

    BigDecimal x = new BigDecimal(0.15); // DON'T DO THIS
    

    因为如果你传入一个双精度数,你也会将双精度数的不准确性传递到新的 BigDecimal 实例中。如果您传入一个字符串,BigDecimal 会知道™ 并做正确的事™。

    【讨论】:

    • 你应该使用 new BigDecimal(0.15) 而不是 BigDecimal.valueOf(0.15)
    • @PeterLawrey 你说得对,我错过了那个。我已经更新了我的答案。
    • 不过,对于“1/3”来说效果不太好。为此,您需要有理数。
    • @Thilo True,但 OP 要求“带小数的基本算术”,而不是“带有理数的基本算术”:)。
    【解决方案3】:
      BigDecimal  a = new BigDecimal(".15");
      BigDecimal  b = new BigDecimal(".01"),
      BigDecimal  c = new BigDecimal(0);
    
      c = a.subtract(b);      
      System.out.println(c);
    

    【讨论】:

      【解决方案4】:

      在使用double 时,您需要应用合理的回合。如果这样做,您可以获得 15 位数的准确度,这在大多数情况下已经足够了。

      double a = 0.15;
      double b = 0.01;
      System.out.printf("%.2f%n", a - b);
      
      double a2 = 0.16;
      double b2 = 0.01;
      System.out.printf("%.2f%n", a2 - b2);
      

      打印

      0.14
      0.15
      

      【讨论】: