Я пытаюсь использовать рекурсивную функцию для вычисления числа Эйлера в 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
потому что вы не можете хранить такое большое число в типе double, используя математику с плавающей запятой.
Float
s и Double
s следуют арифметике насыщенности, то есть, если числа становятся слишком большими, они устанавливаются на бесконечность.
Это потому, что вы пытаетесь вычислить факториал 1000... что довольно много. Факториал 1000
Вы пытаетесь сохранить его в длинном значении, но длинные
максимальное значение намного меньше, чем 1000!
. В принципе уже не подходит.
Рассмотрите возможность использования класса BigInteger (или BigDecimal), он находится в java sdk по умолчанию, и вы можете напрямую выводить через println()
.
Однако вы уже знаете результат, это e, поэтому вам может понадобиться реализовать только Big-Class
для факториала.
Конечно, это должен быть BigDecimal.
Я не слишком уверен, что BigDecimal способен удерживать 1000!, но уверен, что число Эйлера не может отображаться как такой BigInteger
Что ж, оба будут храниться до величины, которую позволит память, и вам понадобится BigDecimal, как только вы выполните деление. Должен признаться, я не удосужился вычислить, является ли конкретно значение 1000! превысит обычную память - может быть, так и будет, но я полагаю, что я вижу вопрос в основном как «как вы вычисляете с большим количеством терминов / точности, чем уместится в двойном», а не конкретно о числе 1000.
1000! не превысит типичную память, так как имеет только 2568 цифр и очень быстро вычисляет. Но я бы не стал каждый раз пересчитывать. Просто не используйте рекурсию. Начните с 1 и используйте это значение, затем разделите его на 2, затем на 3, затем на 4. Таким образом, каждый последующий член в вычислении имеет только 1 дополнительное деление.
Я знаю, я написал целую программу с факториалами. Но для меня Java ушел в отставку, и я продолжаю работать с C++, потому что с 100,000,000!
он в 30 раз быстрее.
Вы превышаете возможности 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);
}
}
даже если я ввожу большие числа после некоторого терпения, я получаю результаты без исключения.
Верхний предел 65, когда я ввожу 66, я получаю бесконечность.