Почему я теряю точность Bigdecimal? - PullRequest
0 голосов
/ 24 октября 2018

Я конвертирую числа типа 5.326.236,56 (деньги) из txt и сначала удаляю точки и запятые, но теряю десятичные дроби, и я уже определил столбцы как:

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

но я теряю последние 2 цифры, которые соответствуют Decimal части

Вот мой код:

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;
}

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Во-первых, ваша логика преобразования странная:

Вы отбираете все -, , и . из вашей строки и предполагаете, что она составляет 2 десятичных знака при построении BigDecimal.

Это означает, что, если вам дана строка 1234.5678, вы собираетесь построить 123456.78 в качестве результата.

В зависимости от ваших намерений, вот ответы:

  1. Если вы хотите преобразовать в BigDecimal на основе значения во входной строке

    Что означает, что если вы хотите, чтобы String "1,234.5678" стала 1234.5678 в BigDecimal, вы могли бы сделатьиспользование DecimalFormat, как описано в этом вопросе: https://stackoverflow.com/a/18231943/395202

  2. Если странная логика - то, что вы намеревались сделать

    Что означает, если вы хотите String "1,234.5678"чтобы стать 123456.78 в BigDecimal, особая проблема в вашем коде заключается в том, что вы делаете длинное деление и используете результат для создания BigDecimal.

    В Java (и многих других языках) деление целого числа на целоесобирается дать вам целое число в результате, так что 123456 / 100 даст вам 1234.

    То, чего вы хотите достичь, может быть сделано с помощью

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

    Возвращаясь к вашему коду, существует множество других проблем:

    1. Ваша логика конкатенации строк крайне неэффективна.Вы можете использовать StringBuilder (или другой способ, который я предлагаю в ближайшее время)
    2. Вам не нужно преобразовывать символ в строку для сравнения.Таким образом, вы должны написать

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

      if (c != '.') {
      
    3. Вы можете просто использовать регулярное выражение для очистки введенной строки:

      String cvalue = stringNumber.replaceAll("[.,-]", "");
      
0 голосов
/ 24 октября 2018

По сути, вы делаете целочисленное деление на long перед построением BigDecimal.

Естественно, целочисленное деление производит еще одно 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 ... напрямую ... без разбивки строк, чтобы избавиться от запятой и символов точки.(И вам не нужно предполагать, что входной номер имеет ровно две цифры после десятичной дроби.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...