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)
        return total
Asked By: Ruby Gloom

||

Answers:

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
    return total

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

Output:

0.5833333333333333
0.7833333333333332
Answered By: Tim Roberts

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
    return total

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
    return total

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
    return total
Answered By: Mark Tolonen

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
from operator import add, sub

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

def calc(stop=0.199):
    c = cycle((sub, add))
    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

Answered By: Cobra

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)]
Answered By: Pierre D
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.