# Arithmetic/Geometric series calculator

I've written a small program that calculates Arithmetic and Geometric Partial Sums. I'd like feedback on anything possible, since I intend on writing a cheatsheet that encapsulates all PreCalculus equations.

partial_sum.py

"""
This is a program that calculates arithmetic and geometric
partial sums

"""

from fractions import Fraction

def find_an(parsed_series):
"""
Finds an in the passed parsed arithmetic series

:param parsed_series: The series to be analyzed

"""
for i, _ in enumerate(parsed_series):
if parsed_series[i] == ".":
return int(parsed_series[i + 1])
return None

def arithmetic_partial_sum(series):
"""
Returns the partial sum of an arithmetic series

Formula:
S = n( (a1 + an) / 2 )

Find an:
an = a1 + (n - 1)d

Find n:
n = 1 + ( (an - a1) / d )

:param series: Arithmetic series to solve

"""

series = series.split("+")

a1 = int(series)
d = int(series) - a1
an = find_an(series)
n = 1 + ((an - a1) / d)
S = n * ((a1 + an) / 2)

return S

def geometric_partial_sum(series):
"""
Returns the partial sum of the geometric series

:param series: Geometric series to solve

Formula:
S = (a1 * (1 - (r ** n))) / (1 - r)

"""

series = series.split("+")

a1 = int(series)
r = int(series) / a1
n = len(series)
S = (a1 * (1 - (r ** n))) / (1 - r)

return str(Fraction(S).limit_denominator())

if __name__ == '__main__':
A_SERIES = "3+7+11+15+.+99"
G_SERIES = f"3+1+{1/3}+{1/9}+{1/27}+{1/81}"
print(arithmetic_partial_sum(A_SERIES))
print(geometric_partial_sum(G_SERIES))


find_an() looks like an internal function, used by arithmetic_partial_sum(). If it is not for external use, it should be named with a leading underscore, to suggest it is private.

arithmetic_partial_sum() appears to handle only integer values, yet it return a floating-point value (1275.0 in the built-in example). It should return an integer, since it is adding up integers. Use the Python3.x integer-division operator: //.

    n = 1 + (an - a1) // d
S = n * (a1 + an) // 2


Or, not assume the terms are integer, and use float(...) instead.

geometric_partial_sum() fails if the first 2 values are not int values:

>>> geometric_partial_sum(f"1+{1/3}+{1/9}+{1/27}+{1/81}")
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
geometric_partial_sum(f"1+{1/3}+{1/9}+{1/27}+{1/81}")
File "...\partial_sum.py", line 63, in geometric_partial_sum
r = int(series) / a1
ValueError: invalid literal for int() with base 10: '0.3333333333333333'


You should convert the terms to floating-point values, not integers:

    a1 = float(series)
r = float(series) / a1


find_an() assumes $$\a_n\$$ is immediately after the '.' term, so will fail with:

arithmetic_partial_sum("3+7+11+15+.+95+99")
arithmetic_partial_sum("3+7+11+15+19")


Why not just retrieve the last term?

def find_an(parsed_series):
return int(parsed_series[-1])


Now the following all succeed and return the correct values

arithmetic_partial_sum("3+7+11+15+.+95+99")
arithmetic_partial_sum("3+7+11+15+...+95+99")
arithmetic_partial_sum("3+7+11+15+19")


The """docstrings""" for arithmetic_partial_sum() and geometric_partial_sum() appear unhelpful. For example:

>>> help(arithmetic_partial_sum)
Help on function arithmetic_partial_sum in module __main__:

arithmetic_partial_sum(series)
Returns the partial sum of an arithmetic series

Formula:
S = n( (a1 + an) / 2 )

Find an:
an = a1 + (n - 1)d

Find n:
n = 1 + ( (an - a1) / d )

:param series: Arithmetic series to solve


The function is not returning an or n. Even the formula is not particularly helpful. """docstrings""" should tell a user how to use the function. For example (adding Python 3.6 type hints as well):

def arithmetic_partial_sum(series:str) -> int:
"""
Returns the sum of an arithmetic series

Example:
s = arithmetic_partial_sum("1+3+5+.+99")  # returns 2500

:param series: A string representing the arithmetic series to solve
"""


Now type help(arithmetic_partial_sum):

>>> help(arithmetic_partial_sum)
Help on function arithmetic_partial_sum in module __main__:

arithmetic_partial_sum(series: str) -> int
Returns the sum of an arithmetic series

Example:
s = arithmetic_partial_sum("1+3+5+.+99")  # returns 2500

:param series: A string representing the arithmetic series to solve


The user is told the function takes a string and returns an integer. The format of the string should be clear from the example.

One thing to also include is the fact that it also doesn't support series in which each term alternates between positive and negative as the series = series.split("+")

For example in an arithmetic series like 5+3+1-1-3 with a common difference of -2, the way the series = series.split("+") is set up, will make it detect 1-1-3 as a single term.

And in geometric terms, for example: 9-3+1-(1/3)+(1/9), it will again fail to detect the - and mistake 9-3 and 1-(1/3) as complete terms.

A viable solution is to separate every term whether negative or not by a +. Using the two examples above:

• Arithmetic: "5+3+1+-1+-3"
• Geometric: f"9+-3+1+-{1/3}+{1/9}"