Деление лонгов, возвращаемых методом-неправильные значения


У меня есть два метода: степенной и факториальный:

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 3

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