I am creating a sigsum() function which takes the sum using an input equation and an input variable. Here's what I have so far:
def sigsum(eqn, index, lower=0, upper=None, step=1):
if type(step) is not int:
raise TypeError('step must be an integer')
elif step < 1:
raise ValueError('step must be greater than or equal to 1')
if upper is None:
upper = 1280000
if lower is None:
lower = -1280000
if (upper - lower) % step:
upper -= (upper - lower) % step
index = lower
total = 0
while True:
total += eqn
if index == upper:
break
index += step
return total
Usage of function:
print(sigsum('1/(i+5)','i'))
>>> 12.5563
My current problem is converting 'eqn' and 'index' to variables that exist inside the function local namespace. I heard around that using exec is not a good idea and that maybe setattr() might work. Can anyone help me out? Thanks.
For eqn
I suggest using a lambda function:
eqn = lambda i: 1 / (i + 5)
then index
is not needed, because it is just "the variable passed to the function" (does not need a name).
Then your function becomes
def integrate(fn, start = 0, end = 128000, step = 1):
"""
Return a stepwise approximation of
the integral of fn from start to end
"""
num_steps = (end - start) // step
if num_steps < 0:
raise ValueError("bad step value")
else:
return sum(fn(start + k*step) for k in range(num_steps))
and you can run it like
res = step_integrate(eqn) # => 10.253703030104417
Note that there are many steps to this, and many of them involve very small numbers; rounding errors can become a major problem. If accuracy is important you may want to manually derive an integral,
from math import log
eqn = lambda i: 1 / (i + 5)
eqn.integral = lambda i: log(i + 5)
def integrate(fn, start = 0, end = 128000, step = 1):
"""
Return the integral of fn from start to end
If fn.integral is defined, used it;
otherwise do a stepwise approximation
"""
if hasattr(fn, "integral"):
return fn.integral(end) - fn.integral(start)
else:
num_steps = (end - start) // step
if num_steps < 0:
raise ValueError("bad step value")
else:
return sum(fn(start + k*step) for k in range(num_steps))
which again runs like
res = step_integrate(eqn) # => 10.150386692204735
(note that the stepwise approximation was about 1% too high.)