in scripts/util.py [0:0]
def find_ratio(a, n, s, r0=None):
"""given the start (a), count (n), and sum (s), find the ratio required"""
if n == 2:
return s / a - 1
an = a * n
if n == 1 or s == an:
return 1
if r0 is None:
# we only need to know which side of 1 to guess, and the iteration will work
r0 = 1.1 if an < s else 0.9
# geometric sum formula
def f(r):
return a * (1 - r**n) / (1 - r) - s
# derivative of f
def df(r):
rm1 = r - 1
rn = r**n
return (a * (rn * (n * rm1 - r) + r)) / (r * rm1**2)
MIN_DR = 0.0001 # negligible change
r = r0
# print(f"r(0)={r0}")
MAX_TRIES = 64
for i in range(1, MAX_TRIES + 1):
try:
dr = f(r) / df(r)
except ZeroDivisionError:
log.error(f"Failed to find ratio due to zero division! Returning r={r0}")
return r0
r = r - dr
# print(f"r({i})={r}")
# if the change in r is small, we are close enough
if abs(dr) < MIN_DR:
break
else:
log.error(f"Could not find ratio after {MAX_TRIES}! Returning r={r0}")
return r0
return r