Добавление дробей с помощью рекурсии

Мне нужно написать рекурсивный метод для вычисления следующего ряда:

m(i) = 1/3 + 2/5 + 3/7 + 4/9 + 5/11 + 6/13 + .... + i/(2i + 1)

Затем мне нужно написать программу, которая отображает m(i) вместо i = 1,2,....10.

Я понимаю основную идею рекурсии. До сих пор я сделал 2 программы: одну для факториалов и одну для последовательности чисел Фибоначчи. Эта проблема поставила меня в тупик.

Это то, что у меня есть до сих пор.

public static void main(String[] args) {
    for (int i = 1; i <= 10; i++) {
        System.out.println(m(i));
    }
}

public static double m(int i) {
    if (i == 1)
        return 1;
    else
        return ???;
}

person BluceRee    schedule 09.04.2013    source источник
comment
Где ты застрял? Что у вас есть до сих пор?   -  person thegrinner    schedule 10.04.2013
comment
@thegrinner обновил его для тебя.   -  person BluceRee    schedule 10.04.2013
comment
Как уже говорилось, эта проблема не подходит для рекурсии. Однако может случиться так, что последовательные числители следуют последовательности с простым рекурсивным определением. Если это правда, то это не столько проблема программирования, сколько математическая задача, и вам может повезти больше на math.stackexchange.com. Если это не так, то это плохая проблема для понимания рекурсии.   -  person dspyz    schedule 10.04.2013


Ответы (2)


Во-первых, похоже, что ваш базовый регистр выключен — это должно быть 1/3 (первое число в ряду).

В противном случае вы должны вернуть следующий шаг вниз, добавленный к текущему шагу. Учитывая вашу серию, текущий шаг — i/(2i + 1).

public static double m(int i) {
  if (i == 1) {
    // Base case is 1 - return the first number in the series
    return 1/3;
  } else {
    // Get the current step (ie the current iteration of m(i))
    double curStep = i / (2.0 * i + 1.0);

    // Return the current step plus the next step down
    return curStep + m(i - 1);
  }
} 
person thegrinner    schedule 09.04.2013
comment
Можете ли вы объяснить мне, что такое текущий шаг? @thegrinner - person BluceRee; 10.04.2013
comment
@thegrinner Вероятно, вам следует добавить .0 в несколько мест, чтобы избежать целочисленного деления. - person Lone nebula; 10.04.2013
comment
@BluceRee Текущий шаг является i шагом в вашей серии: i/(2i + 1). Например, m(1) станет 1 / (2 * 1 + 1) или 1/3. m(5) = 5 / (2 * 5 + 1) = 5 / 11. Кроме того, я забыл знак умножения - исправлю это в ответе. - person thegrinner; 10.04.2013
comment
Для меня это печатает 0.0 десять раз. Кроме того, спасибо за объяснение. @thegrinner - person BluceRee; 10.04.2013
comment
@BluceRee Убедитесь, что у вас есть *, о котором я забыл изначально (должно быть i / (2 * i + 1) - person thegrinner; 10.04.2013
comment
На самом деле вы можете сжать это еще больше, поскольку базовый случай на самом деле является сокращением самой формулы. - person Perception; 10.04.2013
comment
@BluceRee Также я был глуп и имел int вместо double - для таких маленьких дробей он округлялся до 0. - person thegrinner; 10.04.2013

Должен ли он быть рекурсивным? если нет, то поможет простой цикл for.

double sum = 0;
for(int x = 0; x < i; x++)
{
    sum += x / (2.0 * x + 1);
}
return sum;

Если он должен быть рекурсивным, вам нужно начать с правильной идентификации базового случая. В этой ситуации ваш базовый регистр может быть либо 0, либо 1. Примеры:

Базовый регистр равен 0:

public static double m(int i)
{
    if(i==0)
        return 0;
    else
    { 
        double sum = i/(2.0 * i + 1);

        return sum + m(i-1);
    }
}

Базовый случай 1:

public static double m(int i)
{
    if(i==1)
        return 1.0/3.0;
    else
    { 
        double sum = i/(2.0 * i + 1);

        return sum + m(i-1);
    }
}
person somethingShiny    schedule 09.04.2013