代码之家  ›  专栏  ›  技术社区  ›  jpp

级数展开的三角函数

  •  1
  • jpp  · 技术社区  · 6 年前

    我正在尝试编写模拟 math.sin math.tan 但是,不是使用 math 库,使用系列展开执行计算。

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

    sin(x)=x^3/3!+x^5/5。。。

    tan(x)=sin(x)/-sin(x)^2

    这是我的尝试,但我不知道如何执行翻转标志 + / - / + /。。。系列扩展的一部分 sin :

    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 但这似乎很混乱。有更好的方法吗?

    笔记 :此问题是 now deleted question 昨天由@Lana发布。

    2 回复  |  直到 6 年前
        1
  •  5
  •   Thierry Lathuille    6 年前

    通过使用前一项计算总和的下一项,可以避免在每一步重新计算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的版本相比,速度大约是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
    
        2
  •  1
  •   jpp    6 年前

    你很接近。下面是一种使用 sum 具有 enumerate 用于您的系列扩展。

    列举 通过获取iterable的每个值并附加一个索引来工作,即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
    

    您可以避免使用三元语句 列举 总共:

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

    如果你手工写出前几个术语,等价性就会变得很清楚。

    备注:

    • 的标志 tan 功能仅适用于第1和第4象限。这与您提供的公式一致。您可以对输入执行简单的转换来解释这一点。
    • 可以通过增加参数来提高精度 n
    • 您也可以在没有库的情况下计算阶乘,但我将把它作为练习。