What exactly is Stop in this question and how do I get the sum?
Question:
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
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
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
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
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
- 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.
- 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.
- We make the series of terms in a list comprehension (for speed).
- (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)]
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
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
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
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
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
- 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 nowfor k in range(1, n + 1)
which will go from 1 ton
, included. - We use the oddness of
k
(k & 1
) to determine the sign of each term, i.e.+1
fork == 1
,-1
fork == 2
, etc. - We make the series of terms in a list comprehension (for speed).
- (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 thansum(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)]