计算积分:一行代码解决方案?

0 投票
3 回答
1920 浏览
提问于 2025-04-17 15:11

我在做一个程序,用来计算一个函数的积分,用户可以指定矩形的数量、起始点和结束点。

注意:我使用的是矩形的左端点。

我的这个功能运行得很好(至少看起来是这样的)。不过,我想看看能不能把它写成一行代码,但不太确定怎么做,因为我在用 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)/nfloat(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)]])

注意,integralintegral2之间有很大的区别: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

当然,应该说,把这个写成一行代码没有其他目的,只是为了(奇怪的?)娱乐 :)

撰写回答