【问题标题】:Why am I losing Bigdecimal precision?为什么我会丢失 Bigdecimal 精度?
【发布时间】:2018-10-24 14:49:25
【问题描述】:

我正在从txt 转换像5.326.236,56(钱)这样的数字,并首先删除点和逗号,但我丢失了小数,我已经将这些列定义为:

@Column(name = "total", precision = 16, scale = 2)
private BigDecimal total;

但我丢失了与 Decimal 部分对应的最后 2 位数字

这是我的代码:

private BigDecimal parseBigLong(String stringNumber) {
    String cvalue = "";
    for (int n = 0; n < stringNumber.length(); n++) {
        char c = stringNumber.charAt(n);
        if (!(".").equals(String.valueOf(c))) {
            if (!(",").equals(String.valueOf(c))) {
                if (!("-").equals(String.valueOf(c))) {
                    cvalue = cvalue + c;
                }
            }
        }
    }
    BigDecimal bigDecimal = ( BigDecimal.valueOf(Long.parseLong(cvalue) / 100));

    return bigDecimal;
}

【问题讨论】:

  • 所以您正在尝试将5.326.236,56 转换为532623656?
  • 也许你应该使用Double 或Float 而不是Long
  • 我将 5.326.236,56 转换为“532623656”,但是当我将该值除以 100 以获得最后 2 个小数位时,Bigdecimal 等于 5326236.00
  • 我总是使用字符串值来实例化BigDecimal:BigDecimal bd = new BigDecimal("5326236.56")。这样您就不会失去任何精度。
  • Long.parseLong(cvalue) / 100 给你很长的时间。

标签: java hibernate


【解决方案1】:

基本上,在构造BigDecimal 之前,您是在对long 进行整数除法。

当然,整数除法会产生另一个long ...,它不能代表小数点后的那两个数字。

您可以通过使用BigDecimal 进行除法来避免这种情况:

BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(cvalue))
        .divide(new BigDecimal(100));

或者,如果您不需要强制 cvalue 是有效整数(长)表示的约束:

BigDecimal bigDecimal = (new BigDecimal(cvalue))
        .divide(new BigDecimal(100));

可能有更好的方法。 DecimalFormat 类理解各种(本地化)数字格式。如果您创建一个合适的格式,然后调用setParseBigDecimal(true) 格式的parse 方法将产生一个BigDecimal ... 直接... 没有任何字符串bashing 摆脱逗号和句点字符。 (而且你不需要假设输入的数字在小数点后正好有两位。)

【讨论】:

  • 非常感谢,解释得很好,现在正在水下工作
【解决方案2】:

首先,你的转换逻辑很奇怪:

您正在从您的字符串中删除所有 -、, 和 .,并在构造 BigDecimal 时假定它是 2 位小数。

这意味着,如果给你一个字符串1234.5678,你将构建123456.78作为结果。

根据您的意图,以下是答案:

  1. 如果要根据输入字符串中的值转换成 BigDecimal

    这意味着,如果您希望 String "1,234.5678" 在 BigDecimal 中变为 1234.5678,您可以使用 DecimalFormat,如以下问题所述:https://stackoverflow.com/a/18231943/395202

  2. 如果奇怪的逻辑是你打算做的

    这意味着,如果您希望 String "1,234.5678" 在 BigDecimal 中变为 123456.78,则代码中的具体问题是您正在执行长除法,并使用结果来构造 BigDecimal。

    在 Java(和许多其他语言)中,整数除以整数会得到整数,所以 123456 / 100 会得到 1234。

    你想要达到的目标可以通过

    BigDecimal result = BigDecimal.valueOf(longValue).divide(BigDecimal.valueOf(100));
    

    回到你的代码,还有很多其他的问题:

    1. 您的字符串连接逻辑非常低效。您可以使用 StringBuilder(或我很快建议的其他方式)
    2. 您无需将 char 转换为 String 即可进行比较。所以你

      if (!(".").equals(String.valueOf(c))) {
      

      应该写

      if (c != '.') {
      
    3. 您可以简单地使用正则表达式来清理您的输入字符串:

      String cvalue = stringNumber.replaceAll("[.,-]", "");
      

【讨论】:

  • 我总是得到两位小数精度的数字,而不是三位或更多,然后改进代码,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2020-05-02
  • 2019-10-23
  • 2017-01-31
  • 1970-01-01
  • 1970-01-01
  • 2013-06-17
  • 2020-07-28
  • 1970-01-01
相关资源
最近更新 更多