Вычисление экспоненты

Вычисляю экспоненту по формуле Тейлора:

long double cust_exp(double x) {
    long double rememberX = x;
    long double returnValue = 1. + x;
   /* for (int k = 2; k <= 150; k++) {
        x = x * rememberX;
        returnValue = returnValue + x/fact(k);
    }*/
    returnValue = 1;
    for (int i = 150; i > 0; --i) {
        returnValue = 1. + x * returnValue / i;
    }
    return returnValue;
}

long double fact(int k) {
    long double n = 1;
    long double returnValue = 0;
    for (int i = 1; i <= k; i++) {
        n = n * i;
    }
    returnValue = n;
    return returnValue;
}

Закоменченное это то же самое через факториал, только из-за факториала дольше. Нужно с точностью до 6ти знаков после запятой по сравнению с оригинальной функцией. Но вот при степенях больше 20 начинаются расхождения уже на 6м знаке. Есть ли какой-то другой способ расчёта, более точный?


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

NB: скорее всего все версии достаточно точны. Проблема в том что double не может представлять большие числа достаточно точно.

Так будет точнее:

double exp_(double x) {
    double sum = 1;
    double term = 1;
    for (int i = 1; i < 150; ++i) {
        term *= x / i;
        sum += term;
    }
    return sum;
}

Ещё лучше для больших экспонент использовать формулу ex = (ex/2)2.

Проанализируем ошибку для x = 22.

exp (22) = 3584912846.13159179687500000000
exp_(22) = 3584912846.13159275054931640625
разница  = 9.5367431640625 * 10^-7
относительная ошибка: 2.66 * 10^-16

Это очень маленькая ошибка. Например, относительная ошибка между соседними вещественными числами равна 2.22 * 10^-16. То есть, наша функция почти рядом с библиотечной, отличаются только два последних бита мантиссы.

→ Ссылка