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.
Asked
Active
Viewed 3,402 times
-1
-
1Well, show us what you've tried. – PaulMcKenzie Aug 05 '14 at 21:36
-
1Hint: 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 Answers
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