级数展开的三角函数

Trigonometry functions from series expansion

我正在尝试编写模拟 math.sinmath.tan 的函数,但是我没有使用 math 库,而是使用级数展开来执行计算。

公式来自 Mathematics SE,How would you calculate the Tangent without a calculator?:

sin(x) = x − x^3/3! + x^5/5! −...

tan(x) = sin(x) / √(1 − sin(x)^2)

这是我的尝试,但我不知道如何执行符号翻转 + / - / + / ... [的系列扩展的一部分=17=]:

from math import factorial

res = 0
for i in [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]:
    res += 1**i/factorial(i)

print(res)  # 1.1752011936438016

结果不正确,因为我没有应用 + / - 开关。我可以添加一个 if / else 子句,但这看起来很乱。有没有更好的方法?

注意:这个问题是@Lana昨天发的now deleted question的美化版

你很接近。下面是使用 sumenumerate 进行系列扩展的一种方法。

enumerate 通过获取可迭代的每个值并附加一个索引来工作,即第一项为 0,第二项为 1,等等。然后我们只需要测试索引是否为偶数或奇数并使用 ternary statement.

此外,您可以使用 range 而不是列出扩展中所需的奇数。

from math import factorial

def sin(x, n=20):
    return sum(x**j/factorial(j)*(1 if i%2==0 else -1)
               for i, j in enumerate(range(1, n, 2)))

def tan(x):
    return sin(x) / (1-(sin(x))**2)**0.5

print(tan(1.2))  # 2.572151622126318

您可以完全避免对三元语句和 enumerate 的需要:

def sin(x, n=20):
    return sum((-1)**i * x**(2*i+1) / factorial(2*i+1) for i in range(n))

如果您手写前几个术语,等价性就会很清楚。

备注:

  • tan函数的符号只对第一和第四象限是正确的。这与您提供的公式一致。您可以对输入执行一个简单的转换来解决这个问题。
  • 您可以通过增加参数 n 来提高准确性。
  • 你也可以在没有库的情况下计算阶乘,但我会把它留作练习。

您可以通过使用前一项计算和的下一项来避免在每一步重新计算 x**n 和阶乘:

def sin2(x, n=20):
    curr =  x
    res = curr 
    for i in range(2, n, 2):
        curr *= - x**2/(i*(i+1))
        res += curr
    return res

与jpp的版本相比,速度大约是原来的两倍:

from math import factorial

def sin(x, n=20):
    return sum(x**j/factorial(j)*(1 if i%2==0 else -1)
               for i, j in enumerate(range(1, n, 2)))


%timeit sin(0.7)
# 100000 loops, best of 3: 8.52 µs per loop
%timeit sin2(0.7)
# 100000 loops, best of 3: 4.54 µs per loop

如果我们一劳永逸地计算 - x**2,它会变得更快:

def sin3(x, n=20):
    curr =  x
    res = 0
    minus_x_squared = - x**2
    for i in range(2, n, 2):
        res += curr
        curr *= minus_x_squared/(i*(i+1))
    return res

%timeit sin2(0.7)
# 100000 loops, best of 3: 4.6 µs per loop

%timeit sin3(0.7)
# 100000 loops, best of 3: 3.54 µs per loop