解一元方程式的根

在 Python 裡,有一個套件 SymPy 可以用來做數學符號運算,包括解方程式的根。
若系統尚未安裝 SymPy 這個套件,必須先安裝,例如在 Ubuntu 的終端機裡,可以輸入以下指令安裝:
sudo apt install python3-sympy
之後開啟 Spyder,開始使用。

首先我們先匯入需要使用的函式庫:

In [1]: from sympy import solveset, S

In [2]: from sympy.abc import x

求一元二次方程式的根

現在可以開始解方程式,例如,求 x^{2}-1 = 0 的根,得到 -1 和 1 兩個根。

 In [9]: solveset(x ** 2 - 1, x)
 Out[9]: 
 FiniteSet(-1, 1)

x^{2} - x - 6 = 0 的根:

 In [11]: solveset(x ** 2 - x - 6, x)
 Out[11]: 
 FiniteSet(-2, 3)

x^{2} + 1 = 0 的根,得到虛數 i 和 –i

 In [12]: solveset(x ** 2 + 1, x)
 Out[12]: 
 FiniteSet(I, -I)

2x^{2} + 5x + 3 = 0 的根:

 In [15]: solveset(2 * x ** 2 + 5 * x + 3, x)
 Out[15]: 
 FiniteSet(-3/2, -1)

x^{2} + x + 3 = 0 的根:

 In [16]: solveset(x ** 2 +  x + 3, x)
 Out[16]: 
 FiniteSet(-1/2 - sqrt(11)*I/2, -1/2 + sqrt(11)*I/2)

x^{2} + 5 x + 3 = 0 的根:

 In [17]: solveset(x ** 2 + 5 * x + 3, x)
 Out[17]: 
 FiniteSet(-5/2 - sqrt(13)/2, -5/2 + sqrt(13)/2)

求一元三次方程式的根

我們也可以解一元三次方程式的根。
例如,分別求以下方程式的根:

x^{3} - 1 = 0

x^{3} + 1 = 0

x^{3} - 2 x^{2} + 3 x - 2 = 0

 In [24]: solveset(x ** 3 - 1, x)
 Out[24]: 
 FiniteSet(1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2)
 

 In [25]: solveset(x ** 3 + 1, x)
 Out[25]: 
 FiniteSet(-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2)
 

 In [26]: solveset(x ** 3 - 2 * x ** 2 + 3 * x - 2, x)
 Out[26]: 
 FiniteSet(1, 1/2 - sqrt(7)*I/2, 1/2 + sqrt(7)*I/2)

求一元四次方程式的根

我們也可以解更高次的一元方程式的根,例如解以下的一元四次方程式,得到 4 個解。由此可見電腦的威力。

x^{4} - 2 x^{3} + 3 x^{2} - 2 x + 5 = 0

 In [28]: solveset(x ** 4 - 2 * x ** 3 + 3 * x ** 2 - 2 * x + 5, x)
 Out[28]: 
 FiniteSet(1/2 + 73**(1/4)*sin(atan(8/3)/2)/2 - 73**(1/4)*I*cos(atan(8/3)/2)/2, 1/2 + 73**(1/4)*sin(atan(8/3)/2)/2 + 73**(1/4)*I*cos(atan(8/3)/2)/2, -73**(1/4)*sin(atan(8/3)/2)/2 + 1/2 - 73**(1/4)*I*cos(atan(8/3)/2)/2, -73**(1/4)*sin(atan(8/3)/2)/2 + 1/2 + 73**(1/4)*I*cos(atan(8/3)/2)/2)

用數值解表示求出來的根

我們時常需要方程式的數值解,希望計算的結果以浮點數表示。此外,在高次的一元方程式,時常未必會有精確的公式解,這時我們也只能用數值解來表示。在 SymPy 中,提供了方便的數值計算方式,可以用 (expr).evalf() 這個函數,或是用 N(expr) 這 2 種方式。例如:

 In [1]: from sympy import *

 In [2]: from sympy.abc import x

 In [3]: solveset(x ** 2 + 5 * x + 3, x)
 Out[3]: 
 FiniteSet(-5/2 - sqrt(13)/2, -5/2 + sqrt(13)/2)

 In [4]: solveset(x ** 2 + 5 * x + 3, x).evalf()
 Out[4]: 
 FiniteSet(-4.30277563773199, -0.697224362268005)

 In [5]: N(solveset(x ** 2 + 5 * x + 3, x))
 Out[5]: 
 FiniteSet(-4.30277563773199, -0.697224362268005)

可以用 .evalf(n) 或 N(expr, n) 指定輸出的小數點精確度。

 In [6]: solveset(x ** 2 + 5 * x + 3, x).evalf(6)
 Out[6]: 
 FiniteSet(-4.30278, -0.697224)
 
 In [7]: N(solveset(x ** 2 + 5 * x + 3, x), 6)
 Out[7]: 
 FiniteSet(-4.30278, -0.697224)

帶有虛數的根,也可以表示。如:

 In [8]: solveset(x ** 2 +  x + 3, x)
 Out[8]: 
 FiniteSet(-1/2 - sqrt(11)*I/2, -1/2 + sqrt(11)*I/2)
 
 In [10]: solveset(x ** 2 +  x + 3, x).evalf()
 Out[10]: 
 FiniteSet(-0.5 - 1.6583123951777*I, -0.5 + 1.6583123951777*I)

 In [11]: N(solveset(x ** 2 +  x + 3, x))
 Out[11]: 
 FiniteSet(-0.5 - 1.6583123951777*I, -0.5 + 1.6583123951777*I)

一元五次方以上的方程式,未必會有公式解,這時如果輸入無法計算正確公式解的方程式,系統會傳回 CRootof() 的字樣。此時仍可以計算數值解。例如:

 In [18]: solveset(x ** 5 +  9 * x ** 2 - 7, x)
 Out[18]: 
 FiniteSet(CRootOf(x**5 + 9*x**2 - 7, 0), CRootOf(x**5 + 9*x**2 - 7, 1), CRootOf(x**5 + 9*x**2 - 7, 2), CRootOf(x**5 + 9*x**2 - 7, 3), CRootOf(x**5 + 9*x**2 - 7, 4))
 
 In [19]: solveset(x ** 5 +  9 * x ** 2 - 7, x).evalf()
 Out[19]: 
 FiniteSet(-1.92255393575455, -0.923195353755875, 0.852996007284856, 0.996376641112782 - 1.90547084829918*I, 0.996376641112782 + 1.90547084829918*I)
 
 In [20]: N(solveset(x ** 5 +  9 * x ** 2 - 7, x))
 Out[20]: 
 FiniteSet(-1.92255393575455, -0.923195353755875, 0.852996007284856, 0.996376641112782 - 1.90547084829918*I, 0.996376641112782 + 1.90547084829918*I)

設定數學式的輸出格式

在上面的例子,我們看到程式計算出的結果,有時並不容易閱讀,而且可能造成運算符號先後次序的誤解。SymPy 裡提供了其它顯示的設定選項,利用 init_priting() 這個函數,可以讓系統設定較美觀的數學式輸出。

由於 SymPy 數學式的輸出,可以借用一個著名的數學排版軟體 \LaTeX 的格式,所以建議先在系統內安裝 \LaTeX。在 Ubuntu 下,可以在終端機下輸入以下指令安裝:
sudo apt install texlive

回到 Spyder,要輸出較好看的數學式,可以先啟用 init_printing():

 In [3]: from sympy import init_printing

 In [4]: init_printing()

之後,我們再依這篇文章前述方法,來計算方程式的根,會發現輸出的格式不同了。輸出的結果會轉換成較類似數學常用格式的圖檔顯示。

 In [5]: solveset(x ** 2 +  x + 3, x)
 Out[5]: 


 In [6]: solveset(x ** 2 + 5 * x + 3, x)
 Out[6]: 


 In [7]: solveset(x ** 3 - 1, x)
 Out[7]:

在此呈現 IPython console 的畫面截圖,把以下圖檔點開放大欣賞,我們看到前述一元四次方程式的,寫成數學式後,較清楚明瞭了。

參考閱讀:
https://docs.sympy.org/latest/modules/solvers/solveset.html#module-sympy.solvers.solveset

https://docs.sympy.org/latest/modules/evalf.html

https://docs.sympy.org/latest/tutorial/printing.html