在函数中嵌入条件语句

时间:2017-10-22 17:27:16

标签: python function

所以我创建了一个使用泰勒系列近似arctan(x)的函数。如下所示:

def arctan(x,n):

    arctang=0

    for i in range(n):
     sign=(-1)**i
     arctang = arctang + ((x**(2.0*i+1))/(2.0*i+1))*sign

    return arctang

print("arctan(x)=", arctan(x,n))

用户输入介于-1和1之间的x值,以及输入n的整数。但我希望能够扩展函数,以便用户可以输入x的任何值,通过语句

如果x> 0,则arctan(x)=(pi / 2)-arctan(1 / x)

如果x <0,arctan(x)= - (pi / 2)-arctang(1 / x)

所以我将功能更改为以下内容:

import math


def arctan(x, n):
    arctang=0
    inv_x=1/x
    for i in range(n):
     sign=(-1)**i
     arctang = arctang + ((inv_x**(2.0*i+1))/(2.0*i+1))*sign
     if x>0:
        arc_tan=(math.pi/2)-arctang

    else:
        arc_tan=-(math.pi/2)-arctang
    return arc_tan

print("arctan(x)=", arctan(x,n))

但是当我为x和n选择任意值时,例如:x = 1且n = 20,该函数返回的值不正确。我在使用的方程式中没有看到任何错误。

如果有人能发现什么是错的,将不胜感激!

1 个答案:

答案 0 :(得分:0)

这是针对arctangent的Taylor系列的Python 2 / Python 3实现,它使用我在评论中提到的优化。它还处理abs(x) > 1。该系列确实收敛-1 <= x <= 1(尽管当我们接近该范围的端点时,收敛非常慢),但如果我们只使x为正,则更简单。

要使用浮动幂(使用**运算符或pow函数)执行取幂,Python使用对数,这比简单乘法慢,并且它通常比乘法。当然,我们可以通过将x**(2.0*i+1)更改为x**(2*i+1)来消除浮动能力,但最好在可行的情况下避免取幂。

我们可以在这里做到这一点,因为该系列中每个词的x的力量比前一个词的2倍。因此,我们可以在循环外计算,并将其用作循环中的乘数,以计算前一个x所需的每个幂。

此外,这里绝对不需要使用(-1)**i来计算符号。符号在每个术语上交替出现,因此我们可以在循环外初始化sign,然后在每次循环迭代时将其否定。

我的测试代码使用的x值会很快收敛。它调用数学模块中的atan函数来检查我们的近似值与正确值的接近程度。

from __future__ import print_function, division
from math import pi, atan

def arctan(x, terms):
    argsign = -1 if x < 0 else 1
    x *= argsign
    if x > 1:
        x = 1 / x
        inverted = True
    else:
        inverted = False

    result = term = x
    x2 = x * x
    sign = -1
    for i in range(3, 2 * terms, 2):
        term *= x2
        result += sign * term / i
        sign = -sign

    if inverted:
        result = pi / 2 - result
    return argsign * result

# Tests
m = 0.1
terms = 10

print('        x:   arctan(x)           diff')
fmt = '{0:9.5f}: {1:11.8f} {2:14.8g}'

for i in range(1, 10):
    x = m * i
    y = arctan(x, terms)
    print(fmt.format(x, y, y - atan(x)))
print()

for i in range(1, 10):
    x = -m * i
    y = arctan(x, terms)
    print(fmt.format(x, y, y - atan(x)))
print()

for i in range(1, 10):
    x = 1 / (m * i)
    y = arctan(x, terms)
    print(fmt.format(x, y, y - atan(x)))
print()

for i in range(1, 10):
    x = -1 / (m * i)
    y = arctan(x, terms)
    print(fmt.format(x, y, y - atan(x)))
print()

<强>输出

        x:   arctan(x)           diff
  0.10000:  0.09966865 -2.7755576e-17
  0.20000:  0.19739556 -8.3266727e-17
  0.30000:  0.29145679 -4.6035398e-13
  0.40000:  0.38050638 -1.8275848e-10
  0.50000:  0.46364759 -1.8491727e-08
  0.60000:  0.54041871 -7.8657695e-07
  0.70000:  0.61070757 -1.8390105e-05
  0.80000:  0.67446342 -0.00027752053
  0.90000:  0.72981546  -0.0029996458

 -0.10000: -0.09966865  2.7755576e-17
 -0.20000: -0.19739556  8.3266727e-17
 -0.30000: -0.29145679  4.6035398e-13
 -0.40000: -0.38050638  1.8275848e-10
 -0.50000: -0.46364759  1.8491727e-08
 -0.60000: -0.54041871  7.8657695e-07
 -0.70000: -0.61070757  1.8390105e-05
 -0.80000: -0.67446342  0.00027752053
 -0.90000: -0.72981546   0.0029996458

 10.00000:  1.47112767  -2.220446e-16
  5.00000:  1.37340077              0
  3.33333:  1.27933953  4.6029847e-13
  2.50000:  1.19028995  1.8275848e-10
  2.00000:  1.10714874  1.8491727e-08
  1.66667:  1.03037761  7.8657695e-07
  1.42857:  0.96008875  1.8390105e-05
  1.25000:  0.89633291  0.00027752053
  1.11111:  0.84098087   0.0029996458

-10.00000: -1.47112767   2.220446e-16
 -5.00000: -1.37340077              0
 -3.33333: -1.27933953 -4.6029847e-13
 -2.50000: -1.19028995 -1.8275848e-10
 -2.00000: -1.10714874 -1.8491727e-08
 -1.66667: -1.03037761 -7.8657695e-07
 -1.42857: -0.96008875 -1.8390105e-05
 -1.25000: -0.89633291 -0.00027752053
 -1.11111: -0.84098087  -0.0029996458

请注意,编写良好的数学库中的反正切函数使用简单的泰勒级数。有更复杂的算法,对于接近±1的值收敛速度更快,并且不易出现浮点运算的舍入误差。