0

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

我不确定代码应该是什么样子。有人告诉我,我应该只有大约 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’。关于如何改进我的代码的任何建议?

4

3 回答 3

2

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

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尽可能做,这避免了需要调用已经是floata :pifloat

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

然后更改(1.0/2.0)to0.5并删除一些括号:

sum += 0.5 * (pi/n * sin((i-1) * pi/n) + sin(i * pi/n)) * deltax

好多了,嗯?

于 2013-09-29T01:36:37.243 回答
1

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

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

还请记住,您必须在使用它们的值进行赋值之前初始化所有变量。Python 对未命名的变量没有默认值,因此当您引用sumwith sum += exprwhich的值时,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 中,如果您将一个整数类型对象与另一个整数类型对象相除,则无论实际值如何,表达式都会计算为整数。

于 2013-09-29T01:21:25.923 回答
1

使用等距点执行梯形规则的“更好”方法......

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

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

...总和(这是一个区域,所以我将 dA 用于“三角洲区域”)。将 0.5*dx 分解,使整体看起来像:

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

请注意,有两个 f(1) 项,两个 f(2) 项,最多两个 f(n-1) 项。结合这些得到:

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() 是一个内置函数,我将在该行下方使用它。


额外的功劳:sum 的循环部分可以使用生成器表达式和 sum 内置函数一步完成:

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(或接近于 0)。

于 2013-09-29T03:29:48.380 回答