I was working on a program to find the integral of a function, where the user specifies the amount of rectangles, the start, and the stop.
NOTE: I am using left-end points of the rectangles.
I have the function working perfectly (at least, it seems to be perfect). However, I wanted to see if I could write a one-liner for it, but not sure how because I'm using eval()
. Here is my original code:
def integral(function, n=1000, start=0, stop=100):
"""Returns integral of function from start to stop with 'n' rectangles"""
increment, rectangles, x = float((stop - start)) / n, [], start
while x <= stop:
num = eval(function)
rectangles.append(num)
if x >= stop: break
x += increment
return increment * sum(rectangles)
This works fine:
>>> integral('x**2')
333833.4999999991
The actual answer is 1000000/3
, so my function gives a pretty nice estimate (for only 1000 rectangles).
My attempt at a one-liner:
def integral2(function, n=1000, start=0, stop=100): rectangles = [(float(x) / n) for x in range(start*n, (stop*n)+1)]; return (float((stop-start))/n) * sum([eval(function) for x in rectangles])
However, this isn't a truly a one-liner since I'm using a semi-colon. Also, it's a bit slower (takes a few seconds longer, which is pretty significant) and gives the wrong answer:
>>> integral2('x**2')
33333833.334999967
So, is it possible to use a one-liner solution for this function? I wasn't sure how to implement eval()
and float(x)/n
in the same list comprehension. float(x)/n
achieves a virtual 'step' in the range
function.
Thanks!
def integral2(function, n=1000, start=0, stop=100): return (float(1)/n) * sum([eval(function) for x in [(float(x) / n) for x in range(start*n, (stop*n)+1)]])
Note that there is a big difference between integral
and integral2
: integral2
makes (stop*n)+1-(start*n)
rectangles, while integral
only makes n
rectangles.
In [64]: integral('x**2')
Out[64]: 333833.4999999991
In [68]: integral2('x**2')
Out[68]: 333338.33334999956
In [69]: %timeit integral2('x**2')
1 loops, best of 3: 704 ms per loop
In [70]: %timeit integral('x**2')
100 loops, best of 3: 7.32 ms per loop
Perhaps a more comparable translation of integral
would be:
def integral3(function, n=1000, start=0, stop=100): return (float(stop-start)/n) * sum([eval(function) for x in [start+(i*float(stop-start)/n) for i in range(n)]])
In [77]: %timeit integral3('x**2')
100 loops, best of 3: 7.1 ms per loop
Of course, it should go with say that there is no purpose for making this a one-liner other than (perverse?) amusement :)