Python中的梯形规则

时间:2013-09-29 01:10:48

标签: python numerical-integration

我正在尝试使用Python v.2.7.5编写一个程序,它将计算x = 0和x = pi之间的曲线y = sin(x)下的区域。执行此计算,将x范围的n个分区改变为1到10(包括1和10),并打印近似值,真实值和百分比误差(换句话说,通过增加梯形数来提高精度)。将所有值打印到三位小数。

我不确定代码应该是什么样的。我被告知我应该只有大约12行代码才能完成这些计算。

我正在使用Wing IDE。

这是我到目前为止所拥有的

# base_n = (b-a)/n
# h1 = a + ((n-1)/n)(b-a)
# h2 = a + (n/n)(b-a)
# Trap Area = (1/2)*base*(h1+h2)
# a = 0, b = pi

from math import pi, sin

def TrapArea(n):
for i in range(1, n):
    deltax = (pi-0)/n
    sum += (1.0/2.0)(((pi-0)/n)(sin((i-1)/n(pi-0))) + sin((i/n)(pi-0)))*deltax
    return sum

for i in range(1, 11):
    print TrapArea(i)

我不确定自己是否走在正确的轨道上。我收到一个错误,说“分配前引用的局部变量'sum'。有关如何改进我的代码的任何建议吗?

3 个答案:

答案 0 :(得分:2)

Shashank Gupta回答的原始问题和问题是/n整数除法。您需要先将n转换为float

from math import pi, sin

def TrapArea(n):
    sum = 0
    for i in range(1, n):
        deltax = (pi-0)/n
        sum += (1.0/2.0)*(((pi-0)/float(n))*(sin((i-1)/float(n)*(pi-0))) + sin((i/float(n))*(pi-0)))*deltax
    return sum

for i in range(1, 11):
    print TrapArea(i)

输出:

0
0.785398163397
1.38175124526
1.47457409274
1.45836902046
1.42009115659
1.38070223089
1.34524797198
1.31450259385
1.28808354

请注意,您可以大大简化sum += ...部分。

首先将所有(pi-0)更改为pi

sum += (1.0/2.0)*((pi/float(n))*(sin((i-1)/float(n)*pi)) + sin((i/float(n))*pi))*deltax

然后尽可能pi/n,这样就可以float pi已经float,而无需拨打sum += (1.0/2.0)*(pi/n * (sin((i-1) * pi/n)) + sin(i * pi/n))*deltax

(1.0/2.0)

然后将0.5更改为sum += 0.5 * (pi/n * sin((i-1) * pi/n) + sin(i * pi/n)) * deltax 并删除一些括号:

{{1}}

好多了,嗯?

答案 1 :(得分:1)

您的代码存在一些缩进问题,但这可能只是因为复制粘贴。无论如何,在sum = 0函数的开头添加一行TrapArea可以解决当前错误。但正如@Blender在评论中指出的那样,你有另一个问题,即浮点除法表达式*之后缺少乘法运算符((1.0/2.0))。

请记住,在Python中,表达式并不总是按照您的数学方式进行评估。因此,(a op b)(c)不会像您对数学表达式所期望的那样自动将a op b的结果乘以c。相反,这是Python中的函数调用符号。

另请记住,在使用其值进行赋值之前,必须初始化所有变量。 Python没有未命名变量的默认值,所以当你引用sum sum += expr的值相当于sum = sum + expr时,你试图引用一个名称(sum)根本没有绑定到任何对象。

您的功能的以下修订应该可以解决问题。注意我如何在你想要乘法的每个表达式之间放置乘法运算符(*)。

def TrapArea(n):
    sum = 0
    for i in range(1, n):
        i = float(i)
        deltax = (pi-0)/n
        sum += (1.0/2.0)*(((pi-0)/n)*(sin((i-1)/n*(pi-0))) + sin((i/n)*(pi-0)))*deltax
    return sum

编辑:我还通过在循环的每次迭代中将i转换为float(i)来处理浮点除法问题。在Python 2.x中,如果将一个整数类型对象与另一个整数类型对象分开,则无论实际值如何,表达式都将计算为整数。

答案 2 :(得分:1)

一种“更好”的方法来制作具有等间距点的梯形规则......

dx = pi/n为区间的宽度。另外,让f(i)为sin(i * dx)以缩短下面的一些表达式。然后间隔i(在range(1,n)中)贡献:

dA = 0.5*dx*( f(i) + f(i-1) )

...总和(这是一个区域,所以我使用dA代表“delta area”)。考虑到0.5 * dx,使整体看起来像:

A = 0.5*dx * ( (f(0) + f(1)) + (f(1) + f(2)) + .... + (f(n-1) + f(n)) )

请注意,在最多两个f(n-1)项上有两个f(1)项,两个f(2)项。将这些结合起来:

A = 0.5*dx * ( f(0) + 2*f(1) + 2*f(2) + ... + 2*f(n-1) + f(n) )

除第一项和最后一项外,0.5和2因素取消:

A = 0.5*dx(f(0) + f(n)) + dx*(f(1) + f(2) + ... + f(n-1))

最后,你可以将dx完全排除在最后只做一次乘法。转换回sin()调用,然后:

def TrapArea(n):
    dx = pi/n
    asum = 0.5*(sin(0) + sin(pi))   # this is 0 for this problem, but not others
    for i in range(1, n-1):
        asum += sin(i*dx)
    return sum*dx

将“sum”改为“asum”,或者“area”可能会更好。这主要是因为sum()是一个内置函数,我将在线下使用。


额外功劳:总和的循环部分可以通过生成器表达式和sumin内置函数一步完成:

def TrapArea2(n):
    dx = pi/n
    asum = 0.5*(sin(0) + sin(pi))
    asum += sum(sin(i*dx) for i in range(1,n-1))
    return asum*dx

测试这两个:

>>> for n in [1, 10, 100, 1000, 10000]:
        print n, TrapArea(n), TrapArea2(n)

1 1.92367069372e-16 1.92367069372e-16
10 1.88644298557 1.88644298557
100 1.99884870579 1.99884870579
1000 1.99998848548 1.99998848548
10000 1.99999988485 1.99999988485

第一行是“数字零”,因为math.sin(math.pi)的计算结果大约为1.2e-16而不是零。绘制从0到pi的单个区间,端点确实都是0(或几乎是这样。)