Вычисление значений функции с помощью ряда Тейлора на Си

Задание заключается в том, чтобы посчитать значение функции ln((1+x)/(1-x)) с помощью заданной функции и ряда Тейлора для нее 2(x/1 + x^3/3 + ... + x^(2n+1) / 2n + 1) на определенном отрезке a b, разбитом на n частей(n принимается с stdin), сравнить их. Моя программа неправильно считает значение функции с помощью ряда Тейлора на самой первой итерации(выдает какое-то нереальное значение), а на других итерациях считает все правильно.

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

double macheps()
{

    double e = 1.0;

    while (1.0 + e / 2.0 > 1.0)
        e /= 2.0;
    return e;

}


struct Point
{

    double x;
    double y;

};


double f(unsigned p, double x)
{

    double y = 0.;

    for(unsigned i = 0; i <= p; ++i) {

        y += (2 * (pow(x , 2 * i + 1) / (2 * i + 1)));

    }

    return y;

}

double g(double x)
{

    return log((1 + x) / (1 - x));

}


void TaylorCalculation(unsigned iterationCount, double a, double b, double (*taylor_f)(unsigned, double), double (*real_f)(double))
{

    double step = ( b - a ) / iterationCount;
    struct Point* points = (struct Point*)malloc(sizeof(struct Point) * iterationCount);
    double eps = macheps();
    double x = a;

    for(unsigned i = 0; i < iterationCount; ++i, x+=step) {

        unsigned p = 0;
        while(fabs(real_f(x) - taylor_f(p, x)) > eps * 100)
        {

            points[i].x = x;
            points[i].y = taylor_f(p, x);
            ++p;
            if(p >= 100) {

                break;

            }
        }

        printf("%d| %lf %lf %lf\n", i, x, real_f(x), points[i].y);

    }
}

int main()
{

    unsigned n;
    double a = 0., b = 0.5;
    scanf("%u", &n);
    TaylorCalculation(n, a, b, f, g);

}

Например n = 10, вывод таков:

0| 0.000000 0.000000 139105536617883030000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000.000000

1| 0.050000 0.100083 0.100083

2| 0.100000 0.200671 0.200671

3| 0.150000 0.302281 0.302281

4| 0.200000 0.405465 0.405465

5| 0.250000 0.510826 0.510826

6| 0.300000 0.619039 0.619039

7| 0.350000 0.730888 0.730888

8| 0.400000 0.847298 0.847298

9| 0.450000 0.969401 0.969401

Как можем заметить, на 1-9 итерации все верно, а на 0 бред...


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

Автор решения: KoVadim

Запутанная ошибка, но как всегда классика с вещественной арифметикой:).

Вначале поймем, что именно выводится. А это point[0].y. Смотрим выше и понимаем, что оно должно быть равно x, а также a на первой (нулевой) итерации. Я вначале даже начал на printf грешить. Но потом посмотрел в условие в while

fabs(real_f(x) - taylor_f(p, x)) > eps * 100

А что, если это условие не выполняется? тогда point[0].y будет не инициализировано и там может быть все, что угодно. Например, такое большое число. Как проверить? инициализировать нулем перед while.

Но почему же условие не выполнилось? это уже сложнее. В моих оценках все три части этого выражения равны нулю или очень близки к этому.

eps => 1.0 + e / 2.0 > 1.0 => e/2.0 > 0 - это число все таки скорее всего будет такое, что после деления на два будет ноль (выйдет за пределы double), но все таки какое то маленькое. Два других числа равны нулю. И теперь стает очевидно, что условие ложно. И на том же ideone можно это проверить - https://ideone.com/nN8iiZ

Почему же до этого не было видно? переменная не инициализирована. И она может быть какой угодно, например нулем. А может и больше.

→ Ссылка