4

Столбец excel содержит числа в диапазоне от 1 до 0.0001. Когда оператор в ручную делает суммирование стобца примерно из 10-30 строк получается число 15,028

Я делаю автоматизацию. Мне в программу приходят данные из БД ОРАКЛ. Информация приходит в виде строк. Я преобразую строки в тип Double и суммирую. Сумма тех же строк дает у меня 13,9

Может ли Double округлять значения из-за чего информация теряется и как с этим бороться?

for (String[] rowx : СписокмассивовстрокИзОракл) {
            String key = "комбинация данных по логике автоматизации";
            try {
                if (mapMass.containsKey(key)) {
                    try {
                        double src = 0.0;
                        try {
                            src = Double.valueOf(rowx[timeFakt]); //косяк, данные хранящиеся в ячейке timeFakt могут быть типа 0,0028 или 0,0000034. и они округляются.
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        total = Double.valueOf(mapMassTwo.get(key)) + src;
                        String tf = String.valueOf(total);
                        mapMassTwo.put(key, tf);
                        total = 0.0;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    String tf = rowx[timeFakt];
                    mapMass.put(key, tf );
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
pra_soul_owl
  • 1,964
  • Excel суммирует не то, что показывает, а реальные значения типа double с которыми работает внутри. Показывает он уже округленные значения. – rdorn Dec 24 '17 at 15:39
  • 1
    @Padawan "Пара десятков строк" - и погрешность 15%? Что-то здесь не то. Покажите код и данные. Желательно также записать, какие числа у Вас получаются из этих строк. –  Dec 24 '17 at 16:32
  • @Igor до 50% погрешность суммы при работе с округленными значениями вполне может быть: 1.4 + 1.4 = 2.8 округляем - 3, то же с предварительным округлением слагаемых даст 1 + 1 = 2, вот вам и 50% погрешности на ровном месте. – rdorn Dec 24 '17 at 18:35
  • @rdorn Такое, конечно, возможно, но автор пишет, о результате с дробной частью, поэтому мне кажется, что в вопросе не вся информация. –  Dec 24 '17 at 18:50
  • @Igor информации конечно мало, хотя бы пример исходных данных нужен, на котором такое получается. Но меня смущает именно то, что данные приходят в виде строк - excel не показывает настоящие цифры с которыми работает, их у него можно только через interop-Api забрать, и то не факт – rdorn Dec 24 '17 at 19:06

1 Answers1

5

Да, вполне. Операции с числами с плавающей точкой могут приводить к потерям. Вы можете использовать BigDecimal:

BigDecimal sum = new BigDecimal(0);

while (thereIsNumbers()) {
    BigDecimal number = new BigDecimal(getNextNumberAsStringFromExcel());
    sum = sum.add(number);
}

System.out.println(sum);

При создании BigDecimal важно передавать в конструктор именно строку. Если вы передадите туда представление вашей строки уже в виде double, то могут быть погрешности.

Немного про погрешности: https://habrahabr.ru/post/219595/

selya
  • 4,439
  • Да это решило проблему! – pra_soul_owl Dec 25 '17 at 06:06
  • BigDecimal будет наверное память кушать да? – pra_soul_owl Dec 25 '17 at 06:55
  • 1
    @Padawan Определенно, памяти будет использовано больше, чем для обычной double. Тут описаны все внутренние переменные, в которых хранится состояние BigDecimal. Однако если ваш код работает примерно так, как я описал, то каждую итерацию цикла будет создаваться новый BigDecimal, а старые (по возможности) будут собираться GC. И если вам не нужно работать с миллионами таких переменных, то вам нечего бояться. И вообще, String-представление числа ведь не меньше занимает) – selya Dec 25 '17 at 07:03