Rushy Panchal Rushy Panchal - 3 months ago 8
Python Question

Calculating Integrals: One-liner solution?

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!

Answer
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 :)

Comments