0

Имеется функция ln(x) и ряд (x-1)/x + ((x-1)^2)/(2x^2) + ((x-1)^3)/(3x^3) + ... который к ней приближается. Требуется рассчитать значения в данном x рекурсивно и с помощью ряда. Ни один? ни другой метод не работает, попросту виснет программа(винформ). В чем моя ошибка?

Ряд:

double RowFunction(double x) {
    double sum = 0;
    int i = 1;

    while (fabs(sum - log(x)) > 0.1) {
        sum += pow(x - 1, i) / (i*pow(x, i));
        i++;
    }

    return sum;
}

Рекурсия, где n - кол-во иксов, xs - массив этих иксов, array - массив, в который будут записываться значения найденные рекурсивно:

int RecursionFunction(int i, int n, double xs[], double array[]) {
    if (i < n)
        array[i] = log(xs[i]);
    if (i + 1 < n)
        RecursionFunction(i + 1, n, xs, array);
    return 0;
}
Harry
  • 221,325
  • 2
    Ну так вы бы оттрассировали. У вас, судя по всему, Visual Studio? Там прекрасный отладчик. – VladD Apr 30 '16 at 16:05
  • RecursionFunction зависать по идее не должна. – VladD Apr 30 '16 at 16:07
  • а первая на eval отлично работает https://eval.in/562885 – splash58 Apr 30 '16 at 16:10
  • @splash58 Update: расчет рядом работает – vdublevsky Apr 30 '16 at 16:12
  • с рекурсией воще ниче не понятно. что такое массив иксов, например? почему вы массив заполняете логарифмами , а не элементами ряда? или это совсем другая задача? – splash58 Apr 30 '16 at 16:18
  • @splash58 массив иксов состоит из шагов, введённых из формы, например: старт: 0,6 , финиш : 100, шаг : 0,1 . int n = (финиш - старт) / шаг; – vdublevsky Apr 30 '16 at 16:21
  • рекрсия, как я понимаю, когда вы используете значегние из предыдущего шага. а тут? – splash58 Apr 30 '16 at 16:22
  • давайте по порядку может, при каких значениях зацикливается 1 функция (RowFunction) ? – pavel Apr 30 '16 at 16:23
  • @splash58 про элементы ряда - по-моему это будет по-читерски) Это моя курсовая работа, и единственной ошибкой является эта рекурсия, не пойму что не так. Вот скриншоты: http://imgur.com/a/JxuQn – vdublevsky Apr 30 '16 at 16:24
  • я и сам не знаю, что там не так, и что смотреть в отладке не понимаю.... – splash58 Apr 30 '16 at 16:26

2 Answers2

1

Ваша ошибка в том, что Вы совершенно не понимаете, что хотите от программы. Вы не понимаете рекурсию и смысл разложения в ряд. Например, нельзя в разложении в ряд использовать уже готовую функцию логарифма, потому что именно ЭТУ функцию Вы и реализуете посредством ряда, так делают только тогда, когда предполагается, что встроенной функции (которая на порядки быстрее работает) нету. Далее, вычислять степень на каждом шаге - это жутко плохо. В общем, ошибок у Вас десяток, потому перечислять не вижу смысла, вот более правильные реализации:

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

const double EPS = 1e-10;

double Series_Ln (double x) {
    double sum = 0; 
    const double t = (x-1)/x; // Постоянный множитель
    double y = t; // Общий член без деления на i
    double z = y; // Общий член после деления на i
    int i = 1;

    while (fabs(z) > EPS) {
        sum += z;
        y *= t;
        ++i;
        z = y/i;        
    }

    return sum;
}

double Series_Ln_rec (double x, int i) {
    if (pow((x-1)/x, i)/i<EPS)  return 0.0;
    return (x-1)/x*(1.0/i + Series_Ln_rec(x, i+1));
}

int main ( ) {
  double z = Series_Ln (1.1);  
  double zr = Series_Ln_rec (1.1, 1);  
  printf ( "%lf %lf\n", z, zr);
  return 0;
}

Хотя ИМХО решать эту задачу через рекурсию - это жесть. Моё решение неэффективно, можно передавать множитель через параметры и не возводить в степень всё время, но какое задание - такое и решение. Если задачу именно в таком виде дал преподаватель... я бы в него плюнул.

Zealint
  • 3,958
  • скорее академический вопрос, а какую задачу на рекурсию вы ждали? Я рекурсию в основном только при работе с графами использую (DFS например), но даже это без рекурсии пишется не сильно сложнее. – pavel Apr 30 '16 at 20:09
  • 1
    Есть задачи, где рекурсивное решение намного проще нерекурсивного. Например, алгоритм Карацубы для перемножения длинных чисел. Чтобы написать его без рекурсии, нужно очень хорошо знать математику (тензорное исчисление). То же касается задач, где используется ретроградный анализ и пр. их очень много, не буду перечислять. Но вот такие примитивные ряды... я бы линейкой по пальцам бил, если бы увидел рекурсию там, где цикл в разы проще. – Zealint May 01 '16 at 06:10
0

Не очень улавливаю вашу рекурсию... Я бы делал ее так, например (первое, что пришло в голову и ужасно неоптимально):

double recurLog(double x, int n)
{
    if (n == 1) return (x-1)/x;
    double n_term = 1;
    for(int i = 0; i < n; ++i)
        n_term *= (x-1)/x;
    n_term /= n;
    return recurLog(x,n-1) + n_term;
}

Т.е. сумма(n) = сумма(n-1) + n-й член

Ну, а ряд и того проще:

double serialLog(double x, int n)
{
    x = (x-1)/x;
    double term = x, sum = x;
    for(int i = 2; i <=n; ++i)
        sum += (term *= x)/i;
    return sum;
}

Думаю, что все ваши проблемы в сходимости: вы выбрали неудачный x... Как я понимаю, для сходимости указанного ряда требуется x >= 0.5. Вы для какого x тестировали?

И обратите внимание - нигде не требуется pow.

Harry
  • 221,325