第 8 章 反函數與複合函數¶
本章重點:
- 重新理解「函數」與「輸入 → 輸出」的觀念。
- 複合函數的想法:先做一個函數,再做另一個函數,形成 $f(g(x))$ 或 $g(f(x))$。
- 反函數的想法:能夠「把輸入還原」的函數 $f^{-1}$。
- 使用 Python / SymPy 定義複合函數與求反函數。
- 了解反函數存在的條件(單射、水平線測試、限制定義域)。
- 透過單位換算、編碼與解碼等例子,把這些觀念與生活情境連結。
8.1 函數作為「輸入 → 輸出」的機器¶
我們可以把函數想成一台機器:
- 把數字 $x$ 放進去(輸入)。
- 機器依照規則 $f$ 處理,吐出結果 $f(x)$(輸出)。
在 Python 中,我們可以這樣表示:
def f_python(x):
return 2*x + 3
for val in [0, 1, 5]:
print(f"x = {val}, f(x) = {f_python(val)}")
x = 0, f(x) = 3 x = 1, f(x) = 5 x = 5, f(x) = 13
如果存在另一台機器 $g$,可以把 $f$ 的輸出「還原」成原來的 $x$, 也就是 $g(f(x)) = x$,我們就稱 $g$ 是 $f$ 的反函數,寫作 $g = f^{-1}$。
8.2 複合函數:先做 $g$ 再做 $f$¶
若有兩個函數 $f, g$:
- $g$ 把 $x$ 變成 $g(x)$。
- $f$ 再把 $g(x)$ 變成 $f(g(x))$。
這個新函數稱為複合函數 $f \circ g$,定義為:
$$(f \circ g)(x) = f(g(x)).$$
在 Python 中:
def f(x):
return x**2 + 1
def g(x):
return 3*x - 2
def fog(x): # f ∘ g
return f(g(x))
for val in [0, 1, 2]:
print(f"x = {val}, g(x) = {g(val)}, f(g(x)) = {fog(val)}")
x = 0, g(x) = -2, f(g(x)) = 5 x = 1, g(x) = 1, f(g(x)) = 2 x = 2, g(x) = 4, f(g(x)) = 17
在 SymPy 中,我們可以用 Lambda 與符號變數,直接操作解析式:
import sympy as sp
sp.init_printing()
x = sp.symbols('x', real=True)
f_sym = sp.Lambda(x, x**2 + 1)
g_sym = sp.Lambda(x, 3*x - 2)
fog_sym = sp.simplify(f_sym(g_sym(x))) # f(g(x))
gof_sym = sp.simplify(g_sym(f_sym(x))) # g(f(x))
fog_sym, gof_sym
注意:一般來說 $f(g(x))$ 與 $g(f(x))$ 並不相等, 所以複合函數操作有「順序」的概念。
8.3 使用 subs 做函數複合¶
在 SymPy 中,若函數以「解析式」形式存在,也可以用 subs 來做複合。
例如 $f(x) = x^2 + 1$、$g(x) = 3x - 2$,我們要算 $f(g(x))$:
x = sp.symbols('x', real=True)
f_expr = x**2 + 1
g_expr = 3*x - 2
fog_expr = f_expr.subs(x, g_expr) # 把 f 中的 x 用 g(x) 取代
gof_expr = g_expr.subs(x, f_expr) # 把 g 中的 x 用 f(x) 取代
fog_expr, gof_expr
這種寫法非常直接,適合用在較複雜的函數組合中。
8.4 反函數的直觀:能不能「反推回去」¶
對一個函數 $f$,若存在函數 $g$ 滿足:
- $g(f(x)) = x$(對所有適當的 $x$), -(通常也要求)$f(g(y)) = y$(對所有適當的 $y$),
則稱 $g$ 是 $f$ 的反函數,寫作 $g = f^{-1}$。
例:$f(x) = 2x + 3$。
若要還原 $x$,我們解方程 $y = 2x + 3$:
$x = \dfrac{y-3}{2}$。
因此 $f^{-1}(y) = \dfrac{y-3}{2}$,若改變變數名稱,通常寫成:
$f^{-1}(x) = \dfrac{x-3}{2}$。
x, y = sp.symbols('x y', real=True)
f_expr = 2*x + 3
equation = sp.Eq(y, f_expr)
solution_for_x = sp.solve(equation, x)
equation, solution_for_x
解出的 solution_for_x[0] 是 $x$ 用 $y$ 表示的形式:$x = \dfrac{y-3}{2}$。
若要把它寫成反函數的形式,可以把 $y$ 改回常用的自變數符號(例如 $t$ 或 $x$):
t = sp.symbols('t', real=True)
f_inv_expr = solution_for_x[0].subs(y, t) # 把 y 換成 t
f_inv = sp.Lambda(t, f_inv_expr)
f_inv
我們可以檢查 $f^{-1}(f(x))$ 是否等於 $x$:
check = sp.simplify(f_inv(f_expr)) # f^{-1}(f(x))
check
8.6 非線性例子與定義域限制¶
考慮 $f(x) = x^2$。若不限制定義域,$f$ 並沒有反函數,因為:
$f(2) = 4$ 且 $f(-2) = 4$,輸出 4 對應到兩個輸入。
此時常見的做法是限制定義域,例如只考慮 $x \ge 0$, 這樣就可以定義反函數 $f^{-1}(x) = \sqrt{x}$(只取非負根)。
用 SymPy 嘗試求反函數:
x, y = sp.symbols('x y', real=True)
f_expr = x**2
equation = sp.Eq(y, f_expr)
solution_for_x = sp.solve(equation, x)
equation, solution_for_x
你會得到兩個解:$x = \sqrt{y}$ 與 $x = -\sqrt{y}$, 這反映出若不限制定義域,就無法得到「唯一」的反函數。
通常我們會在題目中指定「限制在 $x \ge 0$」,這樣就選擇 $x = \sqrt{y}$ 這支分支作為反函數。
x = sp.symbols('x', real=True)
f_exp = sp.exp(x)
f_log = sp.log(x)
f_exp, f_log
我們可以驗證 $\log(e^x) = x$:
check1 = sp.simplify(sp.log(sp.exp(x)))
check1
另一方面,$e^{\log x} = x$ 對 $x>0$ 成立:
check2 = sp.simplify(sp.exp(sp.log(x)))
check2
這些等式反映了指數與對數互為反函數的關係。
8.8 利用組合檢查反函數¶
若聲稱某個函數 $g$ 是 $f$ 的反函數,我們可以檢查:
- $f(g(x))$ 是否在適當的定義域上化簡為 $x$。
- $g(f(x))$ 是否也能化簡為 $x$。
例:$f(x) = \dfrac{x-3}{2}$ 與 $g(x) = 2x + 3$。
x = sp.symbols('x', real=True)
f_expr = (x - 3)/2
g_expr = 2*x + 3
fog = sp.simplify(f_expr.subs(x, g_expr)) # f(g(x))
gof = sp.simplify(g_expr.subs(x, f_expr)) # g(f(x))
fog, gof
你可以試著換成其他候選函數,檢查它們是否真的是彼此的反函數。
8.9 啟發性例子一:攝氏與華氏溫度換算¶
日常生活中最經典的反函數例子之一,就是攝氏(°C)與華氏(°F)的換算:
$F = \dfrac{9}{5}C + 32$。
這裡可以把 $f$ 視為「從攝氏到華氏」的函數:
$f(C) = \dfrac{9}{5}C + 32$。
我們想要反函數 $f^{-1}$,從華氏換回攝氏:
用 SymPy 解方程 $F = \frac{9}{5}C + 32$:
C, F = sp.symbols('C F', real=True)
equation_CF = sp.Eq(F, sp.Rational(9, 5)*C + 32)
solution_C = sp.solve(equation_CF, C)
equation_CF, solution_C
解得:$C = \dfrac{5}{9}(F - 32)$,也就是 $f^{-1}(F)$。
我們可以檢查組合:
- 從攝氏 0 度 → 華氏 → 再換回攝氏。
f_CF = sp.Lambda(C, sp.Rational(9, 5)*C + 32) # C → F
f_FC = sp.Lambda(F, sp.Rational(5, 9)*(F - 32)) # F → C
C0 = 0
F0 = f_CF(C0)
C_back = f_FC(F0)
C0, F0, C_back
你可以自己試試看 100°C(水的沸點)或 -40°C(攝氏與華氏相等的溫度), 感受反函數在實際單位換算中的角色。
8.10 啟發性例子二:簡單編碼與解碼¶
想像一個非常簡化的「加密」方式:
- 把每個數字 $x$ 變成 $f(x) = 3x + 1$,稱為「編碼」。
- 想要恢復原始數字,就需要一個「解碼」函數 $g$,使得 $g(f(x)) = x$。
顯然這與之前的線性反函數例子完全相同。
用 Python 實作一個小小的編碼/解碼系統:
def encode(x):
return 3*x + 1
def decode(y):
return (y - 1)/3
data = [5, 10, -2]
encoded = [encode(x) for x in data]
decoded = [decode(y) for y in encoded]
print("原始資料:", data)
print("編碼後:", encoded)
print("解碼後:", decoded)
原始資料: [5, 10, -2] 編碼後: [16, 31, -5] 解碼後: [5.0, 10.0, -2.0]
在真正的資安與密碼學中,編碼與解碼函數會複雜得多, 但「函數與反函數」的概念仍然是核心之一。
8.11 啟發性例子三:複合函數作為流程管線¶
在資料處理或科學計算中,我們常常會依序做一系列的轉換:
- 把原始資料加上某個偏移量(平移)。
- 再把結果乘上一個比例因子(縮放)。
- 可能再套用某種非線性函數(例如對數)。
這就像是有一連串函數 $f, g, h$,我們對輸入 $x$ 做:
$h(g(f(x)))$。
來一個簡單的例子:
- $f(x) = x + 1$(加 1)。
- $g(x) = 2x$(乘 2)。
- $h(x) = \ln x$(取自然對數,定義域 $x>0$)。
組合起來:$H(x) = h(g(f(x))) = \ln(2(x+1))$。
用 SymPy 實作與簡化:
x = sp.symbols('x', real=True)
f = x + 1
g = 2*f # g(f(x)) = 2(x+1)
h = sp.log(g) # h(g(f(x))) = log(2(x+1))
sp.simplify(h)
這種「先做哪個函數,再做哪個函數」的思維,在程式設計中也常被稱為 pipeline(管線) 或 composed functions, 是建構複雜計算流程的一個重要觀念。
8.12 本章小結¶
本章你學到了:
- 複合函數 $f \circ g$ 的定義與實作方式(包含 Python 與 SymPy)。
- 如何使用
subs與Lambda來處理解析式的函數複合。 - 反函數的觀念:能夠「還原輸入」的函數,以及用
solve求反函數的方法。 - 反函數存在需要「一對一」的條件,許多非線性函數需要限制定義域才能有反函數。
- 常見可逆函數:線性、指數與對數,以及它們在單位換算與實際應用中的角色。
- 複合與反函數在日常生活中的例子:溫度換算、編碼解碼、資料處理管線等。
8.13 練習題¶
請在本 Notebook 中新增儲存格,試著完成以下練習:
基本複合函數
令 $f(x) = x^2 + 1$,$g(x) = 2x - 3$。
(a) 手算 $f(g(x))$ 與 $g(f(x))$。
(b) 使用 SymPy 的subs或Lambda計算並簡化,確認與手算結果一致。反函數(線性)
令 $f(x) = -3x + 5$。
(a) 使用代數方法求出 $f^{-1}(x)$。
(b) 用 SymPy 建立方程 $y = -3x + 5$,解出 $x$,寫成反函數形式。
(c) 檢查 $f(f^{-1}(x))$ 與 $f^{-1}(f(x))$ 是否都可以簡化為 $x$。非線性反函數與限制定義域
(a) 令 $f(x) = x^2 - 4$。嘗試用 SymPy 求反函數,觀察結果。
(b) 思考若限制 $x \ge 0$,反函數應該是什麼形狀?
(c) 嘗試畫出 $y = x^2 - 4$ 以及 $y = f^{-1}(x)$ 在平面上的圖形(只取適當的部分), 並觀察它們是否為 $y=x$ 的鏡射。指數與對數
(a) 使用 SymPy 簡化 $\log(e^{2x+1})$。
(b) 使用 SymPy 簡化 $e^{\log(3x)}$(注意定義域條件)。
(c) 解方程 $e^{x} = 7$,寫出 $x$ 的解,並計算其近似數值。單位換算練習
(a) 除了攝氏與華氏外,試著建立公里(km)與英里(mile)的換算函數(1 mile ≈ 1.609 km)。
(b) 寫出km_to_mile與mile_to_km兩個 Python 函數,並檢查它們互為反函數(在計算誤差允許範圍內)。函數作為流程管線
假設某測量數據 $x$ 要經過以下處理:- 先減去偏移量 10(函數 $f(x) = x - 10$)。
- 再除以 2(函數 $g(x) = x/2$)。
- 再取自然對數(函數 $h(x) = \log x$,假設輸入為正)。
(a) 寫出組合函數 $H(x) = h(g(f(x)))$ 的解析式(可用 SymPy 簡化)。
(b) 對幾個不同的 $x$ 值(例如 12, 20, 50)計算 $H(x)$, 並解釋這個流程可能代表什麼樣的資料處理過程。
加分題:反函數是否存在?
(a) 對下列函數,思考是否能在「整個實數軸」上定義反函數,若不行,在哪些區間上可以?
- $f(x) = x^3$
- $g(x) = \sin x$
- $h(x) = x^2 + x$
(b) 嘗試用 SymPy 的繪圖工具畫出它們的圖形,並用「水平線測試」直觀判斷是否一對一。
(c) 選一個你感興趣的函數,自己決定一個適合的定義域,使其在該區間上可逆, 然後嘗試用 SymPy 求出其反函數。