1.4 第一次會話#
本節目標#
- 理解
symbols()的真正意義:宣告「符號」,不是指定變數值 - 完成第一次展開、因式分解與 pretty printing
- 學會精確的
Rational運算 - 認識兩個最常見的新手錯誤
symbols():符號不是變數#
在一般 Python 中,x 一定先被賦值才能使用:
x = 5
x + 1 # 6
但數學裡的 \(x\) 不是「某個值」,而是一個尚未指定的代數符號。SymPy 用 Symbol 物件來表達這個概念:
from sympy import symbols
x = symbols('x')
print(x + 1) # x + 1 ← 不是 6,是保留原樣的表達式!
這行 x = symbols('x') 的意思是:「建立一個名叫 x 的符號物件,並用 Python 變數 x 指向它」。之後所有 SymPy 運算都會把 x 當成未知數處理。可以一次宣告多個:
x, y, z = symbols('x y z')
注意:Python 變數名與符號名不一定要相同,但初學時保持一致最不容易搞混。
第一次展開與因式分解#
學校數學最熟悉的操作來了——展開與因式分解,互為逆運算:
from sympy import symbols, expand, factor
x, y = symbols('x y')
expr = (x + y)**2
print(expand(expr)) # x**2 + 2*x*y + y**2
print(factor(x**2 + 2*x*y + y**2)) # (x + y)**2
也可以直接操作多項式:
print(expand((x + y)**3)) # x**3 + 3*x**2*y + 3*x*y**2 + y**3
print(factor(x**3 - 1)) # (x - 1)*(x**2 + x + 1)
print(factor(x**2 - 5*x + 6)) # (x - 2)*(x - 3) ← 十字交乘一次搞定
SymPy 的輸出是標準化後的表達式,你可以把它存進變數、繼續運算:
e = expand((x + 1)*(x + 2))
print(e.subs(x, 3)) # 20 ← 代入 x = 3
Pretty printing 與 LaTeX 輸出#
在 Jupyter 中,SymPy 預設就會用排版好的數學式顯示結果。若在純終端機環境,可用 init_printing() 開啟文字模式的漂亮排版:
from sympy import init_printing, symbols, sqrt
init_printing()
x = symbols('x')
sqrt(2) / 3 # 顯示 √2 ─── 3(分數形式,而不是 2**(1/2)/3)
想要把結果放進報告或 LaTeX 文件,用 latex() 直接轉換:
from sympy import latex
print(latex((x + y)**2)) # (x + y)^{2}
輸出的 LaTeX 碼貼到任何支援數學排版的文件中,就會變成 \((x + y)^2\) 。
精確算術:Rational#
SymPy 中整數相除是精確的:
from sympy import Rational, sqrt
print(1/3) # 0.3333333333333333 ← 這是 Python float!
print(Rational(1, 3)) # 1/3 ← 這才是 SymPy 分數
print(Rational(1, 3) + Rational(1, 6)) # 1/2
常數也都是精確符號:
from sympy import pi, E
print(pi.evalf(20)) # 3.1415926535897932385(想要幾位就幾位)
print(E**2) # exp(2),保持符號形式
第一個小實驗:展開並因式分解#
把本節所學串成完整流程——展開、代值、再分解:
from sympy import symbols, expand, factor
x = symbols('x')
# 步驟 1:展開
e = expand((x - 2)*(x - 3))
print(e) # x**2 - 5*x + 6
# 步驟 2:代入檢驗(x = 10 時兩邊應相等)
print(e.subs(x, 10)) # 56
print((10 - 2)*(10 - 3)) # 56 ✓
# 步驟 3:因式分解還原
print(factor(e)) # (x - 2)*(x - 3)
# 步驟 4:挑戰三次式
print(factor(x**3 - 8)) # (x - 2)*(x**2 + 2*x + 4)
常見新手錯誤#
錯誤 1:忘記宣告 symbols
from sympy import expand
print(expand((x + y)**2)) # NameError: name 'x' is not defined
修正:先 x, y = symbols('x y')。這是最常見的錯,因為 from sympy import * 加 init_session() 的環境中 x 已存在,讓人誤以為永遠存在。
錯誤 2:把 = 當成等式
from sympy import symbols, solve
x = symbols('x')
solve(x**2 - 4 = 0, x) # SyntaxError!
= 在 Python 是賦值,不能出現在表達式裡。解方程時把等號移項寫成多項式:
print(solve(x**2 - 4, x)) # [-2, 2]
若真的需要表示「等式」這個數學物件,用 Eq:
from sympy import Eq
print(Eq(x**2, 4)) # Eq(x**2, 4),代表方程式 x² = 4
print(solve(Eq(x**2, 4), x)) # [-2, 2]
錯誤 3(順帶一提):混用 float
from sympy import sqrt, simplify
print(simplify(sqrt(2.0)**2)) # 2.0000000000000004 的化簡結果,仍是浮點數
print(simplify(sqrt(2)**2)) # 2 ✓ 精確
原則:在 SymPy 裡,整數與分數都用原樣寫,別手癢加上小數點。
動手實驗#
實驗 1:驗證乘法公式。用 expand 驗證 \((a+b)^2 = a^2 + 2ab + b^2\) 與 \((a-b)(a+b) = a^2 - b^2\) :
from sympy import symbols, expand
a, b = symbols('a b')
print(expand((a + b)**2))
print(expand((a - b)*(a + b)))
實驗 2:因式分解大挑戰。分解下列各式,並用 subs 代數值檢驗:
from sympy import symbols, factor
x = symbols('x')
print(factor(x**2 - 9))
print(factor(x**2 + 7*x + 12))
print(factor(x**4 - 16))
實驗 3:故意犯錯一次——把本節「常見新手錯誤」的錯誤碼原樣執行,讀懂錯誤訊息後修正。能看懂錯誤訊息是重要的程式能力。
實驗 4:用 latex() 把 factor(x**3 - 8) 的結果轉成 LaTeX,貼到 [markdown 編輯器] 中欣賞 \((x - 2)(x^2 + 2x + 4)\) 的排版。
小結與練習#
symbols()宣告的是「代數符號」,Python 變數只是指向它的名字。expand()展開、factor()因式分解、subs()代值,三者構成多項式的基本操作循環。init_printing()開啟漂亮排版,latex()輸出 LaTeX 碼;Rational保證精確分數運算。- 新手三大錯:忘記宣告 symbols、
=與Eq混淆、混入 float 破壞精確性。
練習
- 宣告符號 \(a, b, c\) ,展開 \((a + b + c)^2\) ,數一數結果有幾項。
- 因式分解 \(x^3 + x^2 + x + 1\) (提示:分組後可分解,答案含 \((x+1)\) )。
- 用
Rational計算 \(\frac{1}{2} + \frac{1}{3} + \frac{1}{6}\) ,確認結果為精確值 \(1\) 。 - 寫一段程式:展開 \((x+1)^5\) ,然後代 \(x=2\) 驗證等於 \(3^5 = 243\) 。