跳轉到

4.4 反函數與函數變換#

本節目標#

  • 理解反函數概念,會用 solve / solveset 從 \(y = f(x)\) 反解 \(x\)
  • 掌握平移 \(f(x-a) + b\) 與伸縮 \(af(bx)\) 的圖形效應
  • 動手實驗:從 \(\sin x\) 變換出 \(\sin(2x + \frac{\pi}{3})\) 並畫圖

反函數的概念#

若 \(f\) 是一對一(不同輸入給不同輸出),就能「倒帶」:給定輸出 \(y\) 唯一確定輸入 \(x\) ,這就是反函數 \(f^{-1}\) :

\[ f(f^{-1}(y)) = y, \qquad f^{-1}(f(x)) = x \]

幾何上, \(y = f(x)\) 與 \(y = f^{-1}(x)\) 對稱於直線 \(y = x\) 。求法:令 \(y = f(x)\) ,解出 \(x\) ,交換 \(x, y\) ——用 SymPy 就是 solve:

import sympy as sp
x, y = sp.symbols('x y')

sol = sp.solve(sp.Eq(y, 2*x + 3), x)     # 解出 x
print(sol)                                # [y/2 - 3/2]
finv = sp.Lambda(x, sol[0])
f = sp.Lambda(x, 2*x + 3)
print(sp.simplify(f(finv(x)) - x))        # 0 ← 驗證 f(f⁻¹(x)) = x
print(sp.simplify(finv(f(x)) - x))        # 0

再如 \(f(x) = x^3 + 1\) 是嚴格遞增、實根唯一,反函數為 \((y-1)^{1/3}\) 。但若不是一對一,反函數就不存在:

print(sp.solve(sp.Eq(y, x**2), x))   # [-sqrt(y), sqrt(y)] ← 兩個答案!

解的個數就是「一對一與否」的體檢報告: \(x^2\) 在全體實數上沒有反函數,限制定義域 \(x \ge 0\) 後才有 \(\sqrt{y}\) 。

solveset:解集合介面#

solveset 回傳解集合,可明確指定定義域,正好呼應「限制定義域反函數才存在」:

print(sp.solveset(sp.Eq(y, x**2), x, domain=sp.S.Reals))
# {-sqrt(y), sqrt(y)}

print(sp.solveset(sp.Eq(y, x**2), x, domain=sp.Interval(0, sp.oo)))
# {sqrt(y)}  ← 唯一解

t = sp.Symbol('t')
print(sp.solveset(sp.Eq(y, sp.sin(t)), t,
                  domain=sp.Interval(-sp.pi/2, sp.pi/2)))
# {asin(y)}  ← sin 在此區間的反函數

反函數家族 SymPy 都有現成的:asin、acos、atan、log( \(\ln\) 是 \(\exp\) 的反函數)。


函數變換:平移與伸縮#

新函數 圖形效應
\(f(x - a)\) 向右平移 \(a\) ( \(a>0\) )
\(f(x) + b\) 向上平移 \(b\)
\(a\,f(x)\) 垂直伸縮 \(a\) 倍( \(a<0\) 翻轉)
\(f(bx)\) 水平伸縮 \(\frac{1}{b}\) 倍( \(b>1\) 壓縮)

口訣:「括號內動的是水平方向,且方向相反」—— \(f(x-2)\) 是右移不是左移。

逐個畫圖觀察#

import sympy as sp
import numpy as np
import matplotlib.pyplot as plt

x = sp.Symbol('x')
f_expr = x**2

transforms = [
    ("$f(x-2)$:右移 2",       f_expr.subs(x, x - 2), "r"),
    ("$f(x) + 1$:上移 1",     f_expr + 1,            "b"),
    ("$2f(x)$:垂直放大 2 倍", 2*f_expr,              "g"),
    ("$f(2x)$:水平壓縮一半",  f_expr.subs(x, 2*x),   "m"),
]

xs = np.linspace(-4, 4, 400)
plt.plot(xs, xs**2, "k", lw=2, label="$x^2$")
for label, expr, color in transforms:
    plt.plot(xs, sp.lambdify(x, expr, 'numpy')(xs),
             color, lw=1.5, label=label)
plt.axhline(0, color="gray", lw=0.5)
plt.axvline(0, color="gray", lw=0.5)
plt.ylim(-1, 10); plt.legend(); plt.grid(alpha=0.3)
plt.title("四種基本變換"); plt.show()

觀察: \(f(x-2)\) 頂點移到 \((2,0)\) ; \(f(x)+1\) 整條抬升; \(2f(x)\) 高度翻倍、開口變瘦; \(f(2x)\) 在 \(x=1\) 的高度等於原本 \(x=2\) 處、圖形被壓縮一半。

組合變換的順序#

\(g(x) = a f(b(x - h)) + k\) 可拆步驟:右移 \(h\) → 水平伸縮 \(\frac1b\) → 垂直伸縮 \(a\) → 上移 \(k\) 。subs 鏈正好模擬:

g = x**2
g = g.subs(x, x - 2)     # 右移 2
g = g.subs(x, 2*x)       # 水平壓縮(此時式子為 (2x-2)^2)
g = 3*g + 1              # 垂直放大 + 上移
print(sp.expand(g))      # 12*x**2 - 24*x + 13

dv = sp.solve(sp.Eq(sp.diff(g, x), 0), x)
print(dv, g.subs(x, dv[0]))   # [1] 1 ← 頂點在 (1, 1),右移後被壓縮一半

動手實驗#

從 \(\sin x\) 變換出 \(\sin(2x + \frac{\pi}{3})\) 並畫圖

關鍵整理: \(\sin(2x + \frac{\pi}{3}) = \sin\big(2(x + \frac{\pi}{6})\big)\) ,流程為:壓縮(週期 \(2\pi \to \pi\) )→ 左移 \(\frac{\pi}{6}\) 。

import sympy as sp
import numpy as np
import matplotlib.pyplot as plt

x = sp.Symbol('x')
steps = [
    ("$y = \\sin x$",                  sp.sin(x)),
    ("$y = \\sin(2x)$(週期 π)",      sp.sin(2*x)),
    ("$y = \\sin(2x + \\pi/3)$",       sp.sin(2*x + sp.pi/3)),
]

xs = np.linspace(-2*np.pi, 2*np.pi, 600)
plt.figure(figsize=(10, 5))
for (label, expr), c in zip(steps, ["#999999", "tab:blue", "tab:red"]):
    plt.plot(xs, sp.lambdify(x, expr, 'numpy')(xs),
             color=c, lw=2, label=label)

peak = -sp.pi/6 + sp.pi/4      # 令 2x + π/3 = π/2
plt.axvline(float(peak), color="tab:red", ls=":")
plt.annotate("正峰 $x=-\\pi/12$", (float(peak), 1.05),
             ha="center", color="tab:red")
plt.legend(loc="lower left"); plt.grid(alpha=0.3)
plt.title("從 $\\sin x$ 到 $\\sin(2x + \\pi/3)$")
plt.show()

再驗證最容易搞錯的「順序」問題:

A = sp.sin(2*x + sp.pi/3)         # 先壓縮再「對 x」左移 π/6
B = sp.sin(2*(x + sp.pi/3))       # 先左移 π/3 再壓縮
print(sp.simplify(A - B) == 0)    # False:順序不同結果不同!

進一步挑戰:

  1. 用 solve 求 \(f(x) = \dfrac{x}{x+1}\) 的反函數,畫 \(f\) 、 \(f^{-1}\) 、 \(y=x\) 驗證對稱。
  2. 畫 \(y = 2^x\) 與 \(y = \log_2 x\) 及 \(y = x\) ,觀察反函數鏡射。
  3. 寫 wave(A, b, h, k) 回傳 \(A\sin(b(x-h)) + k\) ,畫出 \(A=3, b=0.5, h=\frac{\pi}{2}, k=2\) 並說出振幅、週期與平衡線。

小結與練習#

  • 反函數存在的前提是一對一;solve/solveset 反解 \(x\) ,解的個數洩漏一對一與否
  • solveset 能指定定義域,明確表達「限制範圍後反函數才存在」
  • \(f(x-a)\) 右移、 \(f(x)+b\) 上移、 \(af(x)\) 縱向伸縮、 \(f(bx)\) 橫向伸縮;括號內方向感相反
  • 組合變換順序錯了位置就錯——用 subs 鏈逐步驗證

練習:

  1. 求 \(f(x) = 3 - 2x\) 的反函數,驗證其圖形與原直線對 \(y=x\) 對稱。
  2. 把 \(y = (x+1)^2 - 3\) 還原成 \(y = x^2\) 的變換步驟,用 expand 逐步驗證。
  3. 求 \(f(x) = \sin(3x - \frac{\pi}{4})\) 的振幅、週期與第一個正峰位置,畫圖確認。
  4. 對 \(f(x) = e^x\) 與 \(f(x) = \ln x\) 畫在同一張圖加上 \(y = x\) ,說明它們互為反函數。