计算积分:一行代码解决方案?
我在做一个程序,用来计算一个函数的积分,用户可以指定矩形的数量、起始点和结束点。
注意:我使用的是矩形的左端点。
我的这个功能运行得很好(至少看起来是这样的)。不过,我想看看能不能把它写成一行代码,但不太确定怎么做,因为我在用 eval()
。这是我最初的代码:
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)
这个代码运行得不错:
>>> integral('x**2')
333833.4999999991
实际的答案是 1000000/3
,所以我的函数给出的估算还不错(只用了1000个矩形)。
我尝试写成一行代码:
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])
不过,这并不算真正的一行代码,因为我用了分号。而且,这个版本稍微慢一点(多花了几秒,这个差别还挺大的),而且给出的答案也不对:
>>> integral2('x**2')
33333833.334999967
那么,是否有可能为这个函数使用一行代码的解决方案呢?我不太确定怎么在同一个列表推导式中实现 eval()
和 float(x)/n
。 float(x)/n
实现了 range
函数中的一个虚拟“步长”。
谢谢!
3 个回答
0
用numpy的linspace来作弊怎么样?
integrate = lambda F, n0, nf: sum([F(x)*(abs(nf-n0)/(abs(nf-n0)*300))for x in np.linspace(n0, nf, abs(nf-n0)*300)])
它需要一个函数F,一个下限n0和一个上限nf。下面是它在0到5之间计算x**2的效果:
In [31]: integrate(lambda x: x**2, 0, 5)
Out[31]: 41.68056482099179
结果非常接近。
编辑:这是我的linspace一行代码。
linspace = lambda lo, hi, step:[lo + (hi-lo)/step*i + (hi-lo)/(step*step-1)*i for i in range(step)]
还有一种方法可以把它变成一个完整的一行积分器。我把这个留给你了,朋友。
2
如果你收到的是一个可以直接调用的Python函数,就不需要使用eval
了。你还可以利用numpy.arange
这个函数来生成一系列浮点数值的列表。
情况一:function
是一个可以调用的Python函数
def integrate(f, n, start, end):
return sum([f(i)*(abs(start-end)/float(n)) for i in np.arange(start, end, abs(start-end)/float(n))])
情况二:function
不是一个可以调用的Python函数
def integrate(f, n, start, end):
return sum([eval(f)*(abs(start-end)/float(n)) for x in np.arange(start, end, abs(start-end)/float(n))])
2
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)]])
注意,integral
和integral2
之间有很大的区别:integral2
会生成(stop*n)+1-(start*n)
个矩形,而integral
只会生成n
个矩形。
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
或许可以把integral
更好地理解为:
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
当然,应该说,把这个写成一行代码没有其他目的,只是为了(奇怪的?)娱乐 :)