Java: BigDecimal ошибочно дает ошибку деления на 0 - PullRequest
0 голосов
/ 16 октября 2019

Я пытаюсь вычислить число Эйлера с высокой степенью точности, используя BigDecimals, но через некоторое время числа становятся настолько маленькими, что JVM выдает ошибку деления на 0. Есть идеи как побороть? Я обнаружил, что блок try-catch всегда вызывается после 34 итераций деления, но я не знаю почему. Формула для числа Эйлера представляет собой бесконечный ряд, поэтому 34 итерации приближают его к фактическому значению e , но не так точно, как хотелось бы. На самом деле он не делится на 0, но, вероятно, JVM слишком мала, чтобы заметить разницу.

    BigDecimal ee = BigDecimal.ZERO;
    for (int k = 0; k < 50; k++) {
        int fact = factorial(k);
        try {
            BigDecimal trial = BigDecimal.ONE.divide(BigDecimal.valueOf(fact), 100, RoundingMode.CEILING);
        } catch (Exception e) {
            System.out.println("---- Div-by-0 error; Iterated " + k + " times ----");
            break;
        }
        ee = ee.add(BigDecimal.ONE.divide(BigDecimal.valueOf(fact), 100, RoundingMode.CEILING));
    }
    System.out.println("\n---- Final: \t\te = " + power(ee, x));
}

Ответы [ 2 ]

2 голосов
/ 16 октября 2019

Ваши факторные вычисления переполнены. Ваш метод factorial должен возвращать int, поскольку вы присвоили возвращаемое значение этого метода для int.

Начиная с 13 происходит переполнение. 13! 6,227,020,800, первое факториальное значение слишком велико, чтобы быть представленным в int. Переполнение представляет это значение как 1932053504. Проблема усугубляется, когда дополнительные значения становятся отрицательными, например, 17! рассчитывается как -288522240.

В конечном итоге в продукте накапливается достаточное число 2, чтобы все биты 1 сдвигались с конца, оставляя 0 (начиная с 34!). Это то, что вызвало ваше деление на ноль ошибок.

Но это всего лишь симптом переполнения, которое уже произошло намного раньше. Используйте BigDecimal для расчета факториала, чтобы избежать переполнения и сохранить точность. Это BigDecimal может быть передано непосредственно в divide без преобразования.

0 голосов
/ 16 октября 2019

Я не думаю, что вы используете правильные типы данных для хранения значений. Используйте BigInteger, поскольку он может хранить до 100! значение в нем.

Int max значения: int 4 байта -2,147,483,648 до 2,147,483,647.

Поскольку вы присваиваете значение, превышающее ограничение, оно будет возвращаться к отрицательному значению и, вероятно, приведет к 0в какой-то момент.

Значения факториала:

01! = 1 02! = 2 03! = 6 04! = 24 05! = 120 12! = 479001600

Максимальное значение Int - 2147483647

13! = 6227020800

...