Расчет е ^ х без использования каких-либо функций - PullRequest
9 голосов
/ 06 мая 2009

Мы должны вычислить е ^ х, используя такую ​​формулу:

e ^ x = 1 + (x ^ 1/1!) + (X ^ 2/2!) ......

Пока у меня есть этот код:

while (result >= 1.0E-20 )
{
    power = power * input;
    factorial = factorial * counter;
    result = power / factorial;
    eValue += result;
    counter++;
    iterations++;
}

Моя проблема сейчас заключается в том, что поскольку факториал имеет тип long long, я не могу действительно хранить число больше 20! так что получается, что программа выводит смешные числа, когда достигает этой точки ..

Правильное решение может иметь значение X не более 709, поэтому e ^ 709 должно вывести: 8.21840746155e + 307

Программа написана на C ++.

Ответы [ 4 ]

32 голосов
/ 06 мая 2009

И x ^ n, и n! быстро увеличивается с n (экспоненциально и суперэкспоненциально соответственно) и вскоре переполнит любой тип данных, который вы используете. С другой стороны, x ^ n / n! падает (в конце концов), и вы можете остановиться, когда он маленький. То есть используйте тот факт, что x ^ (n + 1) / (n + 1)! = (x ^ n / n!) * (x / (n + 1)). Вот так, скажи:

term = 1.0;
for(n=1; term >= 1.0E-10; n++)
{
    eValue += term;
    term = term * x / n;
}

(Код вводится прямо в это поле, но я ожидаю, что он должен работать.)

Редактировать: обратите внимание, что термин x ^ n / n! для больших x некоторое время увеличивается, а затем уменьшается. Для x = 709 оно поднимается до ~ 1e + 306, а затем уменьшается до 0, что соответствует пределам, которые может обрабатывать double (диапазон double равен ~ 1e308, а term*x толкает его) но long double работает нормально. Конечно, ваш окончательный результат e x больше, чем любое из терминов, поэтому, если вы используете тип данных, достаточно большой для размещения результата, все будет в порядке.

(Для x = 709 вы можете просто использовать double, если используете term = term / n * x, но это не работает для 710.)

4 голосов
/ 06 мая 2009

Что произойдет, если вы измените тип factorial с long long на double?

2 голосов
/ 06 мая 2009

Я могу придумать другое решение. Пусть pow(e,x) = pow(10, m) * b где b равно >=1 и < 10, тогда

m = trunc( x * log10(e) )

, где log10(e) - постоянный коэффициент.

и

b = pow(e,x)/pow(10, m ) = pow(e,x)/pow(e,m/log10(e)) = pow (e,x-m/log10(e))

Таким образом вы получаете:

z = x-m/log10(e)

, который будет в диапазоне от 0 до 3, а затем используйте b = pow(e,z), как указано SreevartsR.

и окончательный ответ

b - основание (значащая цифра), а m - мантисса (порядок величины).

это будет быстрее, чем подход SreevartsR, и вам может не потребоваться высокая точность.

Удачи.

Это будет работать даже тогда, когда x меньше 0 и больше отрицательно, в этом случае z будет в диапазоне от 0 до -3, и это будет быстрее, чем любой другой подход.

Поскольку z равно от -3 до 3, и если вам требуются первые 20 значащих цифр, то выражение pow (e, z) может быть оценено до 37 членов только с 3 ^ 37/37! = ~ 3.2e-26.

1 голос
/ 06 мая 2009

Вы представили здесь приложение Схема Хорнера для вычисления полиномов.

...