-1

I'm trying to write a program that reads in from the user the number of terms to be used in calculating the natural logarithm of 2. EX: Log(2) with 5 terms is 1/1 - 1/2 + 1/3 - 1/4 + 1/5. The denominator is increased by 1 with each subsequent term, and addition and subtraction signs alternate between each term. I just can't seem to find the right loop setup to make this work correctly. Any help would be appreciated.

joe
  • 29
  • 1
  • 4
  • 1
    Well, show us what you've tried. – PaulMcKenzie Aug 05 '14 at 21:36
  • 1
    Hint: You can also use a loop that increases the denominator with 2 in each iteration - think how. – MSalters Aug 05 '14 at 21:38
  • @MSalters given the requirement to support a variable number of terms, doing two in each iteration would be problematic – Alnitak Aug 05 '14 at 21:44
  • @Alnitak: It would take a final `if` statement, yes. But we're programmers, writing if statements comes naturally. – MSalters Aug 05 '14 at 21:48
  • You don't need loop to compute this, it is already computed. Just: `long double const ln2 = 0.693147181;` – 101010 Aug 05 '14 at 22:16
  • 1
    @40two you've missed the point - the OP wants to demonstrate the convergence of the series by specifying how many terms to calculate. – Alnitak Aug 05 '14 at 22:36
  • @MSalters in this instance it's computationally simpler not to merge the terms, and slightly more complicated algorithmically to drop out early if the number of terms required is odd. – Alnitak Aug 05 '14 at 22:39
  • @Alnitak Even so, no need for loop either. This can be computed via template meta-programming recursion during compile time. – 101010 Aug 05 '14 at 22:44
  • @40two which _again_ misses the point that the OP wants _a program that reads in from the user the number of terms to be used_. – Alnitak Aug 05 '14 at 22:46
  • @Alnitak I didn't miss the fact though that this low effort question deserves trolling comments rather from an answer... ;) – 101010 Aug 05 '14 at 22:51
  • @40two yes - stop it! ;-) – Alnitak Aug 05 '14 at 22:52
  • @Alnitak: You don't drop out of the loop early. You add the last odd term using a single `if` statement after the loop. – MSalters Aug 06 '14 at 08:22

3 Answers3

1

Use a multiplication factor that toggles from +1 to -1 and then to +1 again as you iterate, then multiply your current 1/n term by that.

double ln2(int terms) {

    double sign = 1.0
    double log = 0.0;

    for (double n = 1; n <= terms; n += 1.0) {
        // calculate your 1/n term here
        log += sign / n;    // == sign * 1.0 / n

        // and reverse polarity for the next iteration
        sign = -sign;
    }

    return log;
}

NB: this series converges very slowly!

Alnitak
  • 334,560
  • 70
  • 407
  • 495
1

You're taking the sum of (-1)^n * -1/n. If you combine two adjacent terms you get

(-1)^(2n-1) * -1/(2n-1) + (-1)^(2n) * -1/(2n) = 1/(2n-1) - 1/(2n) = 1/(4*n^2 - 2*n)

and so you can do

double ln2(int lim) {
    double sum;
    for (int n = 1; n <= lim; n++) {
        sum += 1.0/n/(4*n - 2);
    }
    return sum;
}

This still isn't fast but its convergence behavior is better.

Charles
  • 11,269
  • 13
  • 67
  • 105
  • How is that better convergence than doing each separately? The simple method in my answer requires one addition and one division per iteration (and a negation which is effectively free). Yours requires two divisions, and two add/sub ops (level so far) but also needs an additional multiplication. – Alnitak Aug 05 '14 at 22:42
  • @Alnitak While Charles is doing two of your iterations for every one of his (if you actually read his answer), you are correct in that it is slower. Still, it's a clever answer, no need to take it personally. – scohe001 Aug 05 '14 at 22:44
  • @Josh don't worry, it's not personal - it's just incorrect ;-) I am, of course, aware that his performs two terms per iteration, but it requires more FLOPs in total to do it. – Alnitak Aug 05 '14 at 22:45
  • @Alnitak: I didn't say it was faster, I said that its convergence behavior was better. – Charles Aug 05 '14 at 22:57
  • When written as 1.0/(n*(4*n-2)), the evaluation requires a single floating-point division per two terms and is definitely faster. And a key point is that all terms are positive, giving more stability. –  Aug 06 '14 at 14:34
0

You can have a separate variable, n that you add one to each time, check if it is even with if (n%2 == 0). If that is true, multiply your denominator by -1.

Alice
  • 17
  • 3
  • There's far easier ways of making a variable alternate between -1 and +1 .... – Alnitak Aug 05 '14 at 21:45
  • It's somewaht misleading. You have to multiply your _previous_ denominator with -1, because if it was -1 you have to multiply it with -1 to get 1 back. – MSalters Aug 05 '14 at 21:49