Деление лонгов, возвращаемых методом-неправильные значения
У меня есть два метода: степенной и факториальный:
public static long pow(int x, int n) {
long p = x;
for (int i = 1; i < n; i++) {
p *= x;
}
return p;
}
public static long fact(int n) {
long s = n;
for (int i = 1; i < n; i++ ) {
s *= i;
}
return s;
}
Которые возвращают лонги. Когда я хочу использовать их в новом методе оценки экспоненциальной функции , я получаю неправильные результаты по сравнению с математикой.exp (x). Мой код:
public static void exp(int x, double eps) {
int i = 1;
double pow = 1.0;
double fact = 1.0;
double sum = 0.0;
double temp;
do {
temp = pow/fact;
sum += temp;
pow = pow(x, i);
fact = fact(i);
i++;
}
while (temp > eps);
System.out.println("Check: " + Math.exp(x));
System.out.println("My: " + sum);
}
public static void main() {
int x = 10;
double eps = 0.0000000000001;
exp(x, eps);
}
И выход для x=10:
Проверка: 22026.465794806718
Мой: 21798.734894914145
Чем больше x, тем больше "потеря точности" (не совсем, потому что вы не можете действительно назвать это точный...).
Поворот, когда методыpower иfactorial возвращаютdouble , то выход правильный. Кто-нибудь может объяснить мне, как заставить его работать?
Методыpow иfact должны возвращаться долго, и я должен использовать их вexp (College assignment).
3 ответа:
Если вы попробуете этот метод pow:
public static long pow(int x, int n) { long p = x; System.out.println("Pow: "+x+","+n); for (int i = 1; i < n; i++) { p *= x; System.out.println(p); } return p; }
Вы получаете такой результат:
... Pow: 10,20 100 1000 10000 ... ... 1000000000000000 10000000000000000 100000000000000000 1000000000000000000 -8446744073709551616 7766279631452241920
Длинное значение переполняется:
10^20
слишком велико, чтобы поместиться в длинное.Методыpow иfact должны возвращаться долго, и я должен использовать их вexp (College assignment).
Тогда вы мало что можете сделать, чтобы исправить это. Вы можете создать исключение, если
eps
слишком мал.
Насколько велик типичный размер
x
? Это может быть целочисленное переполнение. Попробуйте изменить все аргументыint
вpow
иfact
наlong
.
Длинные типы данных не могут обрабатывать десятичную точность, поэтому вы ошибаетесь с длинными значениями. Почему бы просто не заставить функции возвращать двойные значения?
Edit: Вот что я придумал:
public static long pow(int x, int n) { double p = x; for (int i = 1; i < n; i++) { p *= x; } return (long)p; } public static long fact(int n) { double s = n; for (int i = 1; i < n; i++ ) { s *= i; } return (long)s; } public static void exp(int x, double eps) { double pow = 1.0; double fact = 1.0; double sum = 0.0; double temp; for(int ii=1; ii < 100; ii++) { pow = pow(x, ii); fact = fact(ii); temp = (double)pow/(double)fact; temp = temp == 1 ? 0 : temp; sum += temp; } System.out.println("Check: " + Math.exp(x)); System.out.println("My: " + sum); } public static void main(final String[] args) { int x = 10; double eps = 0.0000000000001; exp(x, eps); }
Это самое близкое, что вы можете получить, не используя десятичные дроби.
Check: 22026.465794806718 My: 21946.785573087538