【问题标题】:Java BigDecimal / Double precision errorJava BigDecimal / 双精度错误
【发布时间】:2014-06-11 00:28:33
【问题描述】:

我正在尝试在 Java 中模拟 ATM 金额输入,即。假设用户一直输入“1”,显示的数量应该是:

0.00
0.01
0.11
1.11
11.11
111.11

我尝试了 Double 和 BigDecimal 进行处理:

println( ((new BigDecimal(current)).multiply(new BigDecimal(10)).add(new BigDecimal(0.01))).setScale(2, RoundingMode.HALF_UP).toString()) )

println( "" + Double.parseString(current) * 10 + 0.01 )

但是两者似乎都显示了这一点:

0.00
0.01
0.11
1.11
11.1 <<< missing the 0.01 at the end
111.01

它们都是由于精度舍入误差(我认为 BigDecimal 没有这个问题)还是我做错了什么?

【问题讨论】:

  • Is floating point math broken? 的可能重复项
  • 恕我直言,您永远不应该使用 BigDecimals 或 Doubles 作为货币。如果您想要最准确的转换为便士。并直接与他们合作。
  • 您的代码看起来不错,但您的 println 行上的操作顺序可能会搞砸。如果将+ "" 移到末尾会怎样?
  • 同意 Doubles 不应该用于货币,但可以使用 BigDecimals - 在您需要控制舍入并且有时需要一美分/美分的会计系统中,它们是最佳选择。跨度>
  • 如果你用便士工作,你可以使用intBigDecimal 让您在会计和税务计算方面更加灵活。

标签: java double bigdecimal


【解决方案1】:

最简单的选择可能是将输入记录为字符串。每次按键后,将新字符附加到其末尾,并通过创建 BigDecimal 并将其除以 100 来格式化数字。

String input = "111111";
BigDecimal value = new BigDecimal(input).divide(new BigDecimal(100)); // 1111.11

也就是说,我刚刚在循环中尝试了您的代码,它似乎工作正常。您需要发布代码以显示您如何生成current

String current = "0.00";
for (int i = 0; i < 10; i++) {
    current = (new BigDecimal(current).multiply(new BigDecimal(10)).add(new BigDecimal(0.01))).setScale(2, RoundingMode.HALF_UP).toString();
    System.out.println(current);
}

//    0.01
//    0.11
//    1.11
//    11.11
//    111.11
//    1111.11
//    11111.11
//    111111.11
//    1111111.11
//    11111111.11

【讨论】:

    【解决方案2】:

    Java BigDecimal 有一个构造函数,它接受一个双精度数,另一个接受一个字符串。尽管通常建议使用字符串构造函数,但您使用的是双重构造函数。你试过了吗?

    BigDecimal addend = new BigDecimal("0.01");

    有关详细信息,请参阅The Evil Big Decimal Constructor

    【讨论】:

      【解决方案3】:

      比较容易弄乱字符串:

      public void test() {
          String s = "0.00";
          for (int i = 0; i < 5; i++) {
              s = new BigDecimal(s.replaceAll(Pattern.quote("."), "") + "1").divide(ONEHUNDRED).toString();
              System.out.println(s);
          }
      }
      

      这里我删除“.”,添加一个“1”,从中创建一个BigDecimal,然后将其除以 100。

      【讨论】:

        【解决方案4】:

        为什么要即时计算金额?只需存储字符串并在最后解析它。

        // Store user input as string (pseudo code)
        String readUserInput() {
          String accumulator = "";
          while (user input available) {
            accumulator += user input;
          }
          return accumulator;
        }
        
        // Get user input as double
        Double getAmount(String input) {
          return Double.parseDouble( input ) / 100.0;
        }
        
        // Or a BigDecimal too
        BigDecimal getAmount(String input) {
          return new BigDecimal(input).divide(new BigDecimal(100));
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-02-24
          • 1970-01-01
          • 1970-01-01
          • 2013-01-11
          • 2018-09-15
          • 2016-02-21
          • 2015-06-21
          相关资源
          最近更新 更多