EXP для серии Тейлора

Я пытаюсь расширить функцию exp(x) до ряда Тейлора. Вот код:

double CalcExp(){
double eps = 0.0000000000000000001;
double elem = 1.0;
double sum = 0.0;
int i = 1;
sum = 0.0;
do {
    sum += elem;
    elem *= x / i;
    i++;
} while (elem >= eps);
return sum;

}

Проблема в том, что когда я ввожу большой X или отрицательный X, моя программа падает. И когда я ввожу X, например «0,00000000001», результат равен -1.

Нужен совет. Спасибо за помощь.


person Ok-Alex    schedule 19.03.2011    source источник


Ответы (2)


Для больших значений X (около 700 и выше) вы достигнете предела диапазона для удвоений (10 ^ 308) и вызовете бесконечный цикл. Вы ничего не можете с этим поделать, вы должны либо ограничить диапазон ввода X, либо использовать какую-то библиотеку больших чисел, чтобы иметь расширенный диапазон.

Другой обходной путь - добавить это в ваш цикл:

if (sum > 1E305) {
  // we'll most likely run into an infinite loop
  break;
}

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

Я не могу воспроизвести проблему для 0.00000000001, мне просто возвращается 1. Отрицательные значения тоже работают нормально, хотя результат неверен, что кажется ошибкой/ограничением алгоритма. РЕДАКТИРОВАТЬ: Чтобы исправить это, мы можем использовать тот факт, что e^-x совпадает с 1 / e^x.

Код:

#include <stdio.h>

double CalcExp(double x){
  double eps = 0.0000000000000000001;
  double elem = 1.0;
  double sum = 0.0;
  bool negative = false;
  int i = 1;
  sum = 0.0;
  if (x < 0) {
    negative = true;
    x = -x;
  }
  do {
    sum += elem;
    elem *= x / i;
    i++;
    if (sum > 1E305) break;
  } while (elem >= eps);
  if (sum > 1E305) {
    // TODO: Handle large input case here
  }

  if (negative) {
    return 1.0 / sum;
  } else {
    return sum;
  }
}

int main() {
  printf("%e\n", CalcExp(0.00000000001)); // Output: 1.000000e+000
  printf("%e\n", CalcExp(-4));            // Output: 1.831564e-002
  printf("%e\n", CalcExp(-45));           // Output: 2.862519e-020
  printf("%e\n", CalcExp(1));             // Output: 2.718282e+000
  printf("%e\n", CalcExp(750));           // Output: 1.375604e+305
  printf("%e\n", CalcExp(7500000));       // Output: 1.058503e+305
  printf("%e\n", CalcExp(-450000));       // Output: 9.241336e-308
  return 0;
}
person schnaader    schedule 19.03.2011
comment
Ух ты! Еще раз большое спасибо! Этот код работает идеально. Ты спас меня :) - person Ok-Alex; 19.03.2011

Нужен совет.

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

person xan    schedule 19.03.2011