# What exactly is Stop in this question and how do I get the sum?

## Question:

Problem Statement

Edit: I have transcribed the image as suggested although I think some terms are better shown in the picture if anything is unclear here;

This function takes in a positive integer n and returns the sum of the following series Sn, as long as the absolute value of each term is larger than stop.

Sn= 1 − 1/2 + 1/3 − 1/4 + … + (−1)n+1/n + …

You can assume that stop is a float value and 0 < stop < 1.

You need not round the output.

For example, if stop = 0.249, then Sn is evaluated with only four terms.

Sn = 1 − 1/2 + 1/3 − 1/4

For example, if stop = 0.199, then Sn is evaluated with only five terms.

Sn = 1 − 1/2 + 1/3 − 1/4 + 1/5

The built-in function abs() is useful. You should use a while loop.

Test cases:

``````print( alternating_while(0.249) )
print( alternating_while(0.199) )
``````

gives:

``````0.5833333333333333
0.7833333333333332
``````

Now for this question, I want to get the sum of this series based on the conditions stipulated in the question.

My problem is I don’t understand how to type the formula given in the question because I’m not familiar with how the while-loop works. Can someone instruct me on how to?

``````def alternating_while(stop):
total = 0
n = 1
term = 1
while abs(term) > stop:
total= (-1) ** (n + 1) / n + alternating_while(n - 1)
``````

The key is "alternating". You can just increment the current denominator one at a time. If it is odd, you add. Otherwise, you subtract. `abs` is not really required; I’m not sure why they would mention it.

``````def alternating_while(stop):
total = 0
denom = 1
while 1/denom > stop:
if denom & 1:
total += 1/denom
else:
total -= 1/denom
denom += 1

print(alternating_while(0.249))
print(alternating_while(0.199))
``````

Output:

``````0.5833333333333333
0.7833333333333332
``````

No reason to use recursion as it wasn’t mentioned as a requirement. Just check the term in the `while` loop for the stop condition:

Python 3.8+ (for the := operator):

``````def alternating_while(stop):
n = 1
total = 0
while abs(term := (-1)**(n+1)/n) > stop:
total += term
n += 1

print(alternating_while(0.249))
print(alternating_while(0.199))
``````

Output:

``````0.5833333333333333
0.7833333333333332
``````

Pre-Python 3.8 version:

``````def alternating_while(stop):
n = 1
total = 0
while True:
term = (-1)**(n+1)/n
if abs(term) <= stop:
break
total += term
n += 1
``````

Or:

``````def alternating_while(stop):
n = 1
total = 0
term = (-1)**(n+1)/n
while abs(term) > stop:
total += term
n += 1
term = (-1)**(n+1)/n    # redundant
``````

You need to cycle between adding and subtracting. The itertools module has a very helpful cycle class which you could utilise thus:

``````from itertools import cycle

def get_term(d=2):
while True:
yield 1 / d
d += 1

def calc(stop=0.199):
term = get_term()
Sn = 1
while (t := next(term)) > stop:
Sn = next(c)(Sn, t)
return Sn

print(calc())
``````

Output:

``````0.6936474305598223
``````

Note:

The reference in the problem statement to absolute values seems to be irrelevant as no terms will ever be negative

I understand you need to use `while` in this particular problem, and this answer won’t immediately help you as it is probably a few steps ahead of the current level of your course. The hope however is that you’ll find it intriguing, and will perhaps come back to it in the future when you start being interested in performance and the topics introduced here.

``````from math import ceil

def f(stop):
n = ceil(1 / stop) - 1
return sum([(2 * (k & 1) - 1) / k for k in range(1, n + 1)])
``````

#### Explanation

1. First, we want to establish ahead of time `n`, so that we avoid a math evaluation at each loop to decide whether to stop or not. Instead, the main loop is now `for k in range(1, n + 1)` which will go from 1 to `n`, included.
2. We use the oddness of `k` (`k & 1`) to determine the sign of each term, i.e. `+1` for `k == 1`, `-1` for `k == 2`, etc.
3. We make the series of terms in a list comprehension (for speed).
4. (A point often missed by many Pythonistas): building the list using such a comprehension and then summing it is, counter-intuitively, slightly faster than summing directly from a generator. In other words, `sum([expr for k in generator])` is faster than `sum(expr for k in generator)`. Note: I haven’t tested this with Python 3.11 and that version of Python has many speed improvements.

For fun, you can change slightly the loop above to return the elements of the terms and inspect them:

``````def g(stop):
n = ceil(1 / stop) - 1
return [(2 * (k & 0x1) - 1, k) for k in range(1, n + 1)]

>>> g(.249)
[(1, 1), (-1, 2), (1, 3), (-1, 4)]
``````
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.