Java числа Эйлера результат бесконечности

Я пытаюсь использовать рекурсивную функцию для вычисления числа Эйлера в Java. Это нормально, когда я ввожу в эту формулу маленькие числа:

Но когда я пытаюсь ввести большее число, например 1000, я получаю бесконечность. Почему это происходит. Как я могу это исправить.

import java.util.Scanner;

public class enumber {
    public static long fact(int a) {
         if (a <= 1) {
             return 1;
         }
         return a * fact(a - 1);
    }

    public static double calculate(int i) {
        double cresult = Math.pow(fact(i), -1);
        if (i == 0 ) {
            return 1;
        }
        return cresult+calculate(i-1);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);  
        System.out.println("Enter i value: ");
        int i = sc.nextInt();
        double eresult = calculate(i);
        System.out.println(eresult);
    }
}
 

выход;

    Enter i value: 
    1000
    Infinity

Верхний предел 65, когда я ввожу 66, я получаю бесконечность.

Muhammed Mustafa Savar 21.12.2020 19:55

потому что вы не можете хранить такое большое число в типе double, используя математику с плавающей запятой.

OldProgrammer 21.12.2020 19:59
Floats и Doubles следуют арифметике насыщенности, то есть, если числа становятся слишком большими, они устанавливаются на бесконечность.
Turing85 21.12.2020 20:00
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
3
267
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это потому, что вы пытаетесь вычислить факториал 1000... что довольно много. Факториал 1000

Вы пытаетесь сохранить его в длинном значении, но длинные максимальное значение намного меньше, чем 1000!. В принципе уже не подходит.

Рассмотрите возможность использования класса BigInteger (или BigDecimal), он находится в java sdk по умолчанию, и вы можете напрямую выводить через println().

Однако вы уже знаете результат, это e, поэтому вам может понадобиться реализовать только Big-Class для факториала.

Конечно, это должен быть BigDecimal.

Neil Coffey 21.12.2020 21:53

Я не слишком уверен, что BigDecimal способен удерживать 1000!, но уверен, что число Эйлера не может отображаться как такой BigInteger

Zacki 21.12.2020 22:26

Что ж, оба будут храниться до величины, которую позволит память, и вам понадобится BigDecimal, как только вы выполните деление. Должен признаться, я не удосужился вычислить, является ли конкретно значение 1000! превысит обычную память - может быть, так и будет, но я полагаю, что я вижу вопрос в основном как «как вы вычисляете с большим количеством терминов / точности, чем уместится в двойном», а не конкретно о числе 1000.

Neil Coffey 21.12.2020 23:10

1000! не превысит типичную память, так как имеет только 2568 цифр и очень быстро вычисляет. Но я бы не стал каждый раз пересчитывать. Просто не используйте рекурсию. Начните с 1 и используйте это значение, затем разделите его на 2, затем на 3, затем на 4. Таким образом, каждый последующий член в вычислении имеет только 1 дополнительное деление.

WJS 21.12.2020 23:28

Я знаю, я написал целую программу с факториалами. Но для меня Java ушел в отставку, и я продолжаю работать с C++, потому что с 100,000,000! он в 30 раз быстрее.

Zacki 21.12.2020 23:48

Вы превышаете возможности long. Но я бы посоветовал вам решить, какую точность вы хотите для e.

Допустим, вы хотите, чтобы ошибка была меньше .0000001. Продолжайте итерацию для e до тех пор, пока положительная дельта между вашим последним вычислением и предыдущим не станет меньше или равна вашей ошибке.

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

Ответ принят как подходящий

Я решил эту проблему, используя циклы. А для старого алгоритма я изменил тип метода фактов на double. Я избавляюсь от бесконечности. После этого я сталкиваюсь с «StackOverflowError». Что такое StackOverflowError?

Мой новый алгоритм;

import java.util.Scanner;

public class enumber2 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        double fact;
        double eNumber = 0;
        int i = in.nextInt();
        
        while(i>0) {
            fact=1;
            for(int j=1; j<=i; j++) {
                fact = fact * j;
            }
            eNumber = eNumber +(1.0/fact);
            i--;
        }
        eNumber = eNumber +1;
        System.out.println(eNumber);
    }

}

даже если я ввожу большие числа после некоторого терпения, я получаю результаты без исключения.

Другие вопросы по теме