使用sympy计算(m/n)*pi的sin和cos的精确值

问题描述 投票:0回答:1

我想找到大量有理值*pi 的正弦和余弦的精确值。我这样做主要是为了学习新的数学和Python。这是我想出的代码,它运行得很好(在某些条件下)。

from sympy import *
import sympy
from IPython.display import display
from sympy.abc import k, m, n, x
import math
from sympy import init_printing
init_printing() 
print("You are solving for sin and cos of (m/n)pi")
m = int(input("Insert m: "))
n = int(input("Insert n: "))
gcd = sympy.gcd(m,n) #Getting the GCD and dividing by it will make the algorithm have less steps
m = m/gcd
n = n/gcd
prime = primefactors(n) #this outputs an array of all of the factors of n
cosp = sympify(-1) #this is necessary, we set the value of cos(pi) = -1, and format it for sympy
r = int(1)
for p in prime:#the nested loops will go through every factor. The for loop each of the factors,
    while n%p == 0:#the while loop for the repetition of the factors
        r = int(r*p)#the r variable serves as a comparison for the values of the cosine
        n = int(n/p)#dividing by the prime we're checking for will complete the loop
        if p == 2:
            cosp = sqrt((1+cosp)/2)#simple bisection of the cosine formula
        else:
            cosp = (Sum((-1)**k*factorial(p)/(factorial(p-2*k)*factorial(2*k))*x**(p-2*k)*(1-x**2)**k , (k, 0, int((p-1)/2)))).doit()-cosp #check out this explanation: https://brilliant.org/wiki/expansions-of-certain-trigonometric-functions/. This is a version of the cosine formula, where x symbolizes cosine pi, and we bring the cosine value to the other side to get "0 = F(x)"
            expandeq = expand(cosp)
            res = solve(expandeq) #we solve for the roots of the equation
            for root in res:
                if N(sympy.cos(sympy.pi/r), 15) == re(N(root, 15)): #to remove all extra solutions, we check the approximation of each root and verify it is equal to cos(pi/r)
                    if str(root)[0] != "C":
                        cosp = root
sinp = expand(sqrt(1-(cosp**2))) 

cosm = expand(Sum((-1)**k*factorial(m)/(factorial(m-(2*k))*factorial(2*k))*cosp**(m-2*k)*sinp**(2*k) , (k, 0, int(m/2))).doit(), trig = False) #finally, we use the formula again to multiply the cosine of pi/n by m
sinm = expand(sympy.sqrt(1-(cosm**2)), trig=False)
print("Approximation of sine of pi*",m, "/",r,": " , round(math.sin(math.pi*m/r), 15))
display(sinm)
print("Approximation of of cosine pi*",m, "/",r,": " , round(math.cos(math.pi*m/r), 15))
display(cosm)

这对于几乎任何 m 都有效,但对于非常有限的 n 则有效。以下是它可以接受的一些素数的列表:{2,3,5,7,11}。它可以求解 2^k*3^l 形式的任何 n(例如 n = 144),但它会止于区区 25,因为它输出一个五次方程:16x^5-20x^3+5x-sqrt( 5)/4-1/4,其中一个解确实对应于 pi/25 的余弦。有没有办法来解决这个问题?如何扩展这段代码的“域”?

顺便说一句,此代码的目的是学习,非常感谢任何对特定数学公式、程序、手稿或理论(例如伽罗瓦理论,对于高中学生来说需要解开的东西)的任何参考。

python math sympy
1个回答
0
投票

对于任何整数

n
m
,数字
cos(n/m*pi)
sin(n/m*pi)
将是代数数,这意味着它们是具有有理系数的多项式的根。这并不一定意味着这些数字可以使用根式中的显式表达式来表示,因为根据阿贝尔-鲁菲尼定理,这对于所有代数数来说都是不可能的。

SymPy 对于任何

m
n
可以做的是告诉你这个数是(最小多项式)的根的多项式:

>>> print(minpoly(sin(5*pi/13)))
4096*_x**12 - 13312*_x**10 + 16640*_x**8 - 9984*_x**6 + 2912*_x**4 - 364*_x**2 + 13

SymPy 的

roots
函数旨在尽可能获得根的根表达式,但在这种情况下失败(可能是因为不存在这样的根表达式)。相反,SymPy 有一种方法将任何代数数表示为“RootOf”。在这种情况下,看起来像:

In [53]: [rs] = [r for r in real_roots(p) if p.same_root(r, sin(5*pi/13))]

In [54]: rs
Out[54]: 
       ⎛      12          10          8         6         4        2         ⎞
CRootOf⎝4096⋅x   - 13312⋅x   + 16640⋅x  - 9984⋅x  + 2912⋅x  - 364⋅x  + 13, 10⎠

这告诉我们

sin(5*pi/13)
是给定多项式的 10 次根(根据 SymPy 的根编号方案)。此 RootOf 表示是数字的精确表示,尽管有些人可能不认为它是“明确的”。例如,我们可以将此数字计算为任何所需的精度,并获得其最小多项式:

In [55]: rs.evalf(50)
Out[55]: 0.93501624268541482343978459983783072905051746957843

In [56]: print(minpoly(rs))
4096*_x**12 - 13312*_x**10 + 16640*_x**8 - 9984*_x**6 + 2912*_x**4 - 364*_x**2 + 13

这是数字的精确表示,因为它有足够的信息来执行精确计算。 RootOf 表示可以表示所有代数数,并且即使在根式表达式可能的情况下通常也是更好的表示。

您要求提供“精确值”,我已经显示了

rs
,这是数字的精确表示。然而,我们从原始表达式
sin(5*pi/13)
中的精确值开始,大多数人可能更喜欢 RootOf 表示
rs

那么问题是,如果原始表达不是你想要的,那么你如何定义你想要的?

© www.soinside.com 2019 - 2024. All rights reserved.