第 5 章 數列與遞迴關係¶
本章重點:
- 了解「數列」的觀念:以整數 $n$ 為索引的函數 $a_n$。
- 使用 Python 產生數列的前若干項,觀察規律。
- 認識常見的數列:等差數列、等比數列,以及其通項與部分和公式。
- 了解「遞迴關係」如何定義數列,並用程式與 SymPy 解線性遞迴。
- 把數列視為「離散函數」,與現實情境(存款、人口、誤差)連結。
在 Jupyter Notebook 中,數列是一個非常適合實驗與觀察的主題, 你可以用程式快速生成大量項目,來驗證自己的猜想。
5.1 數列的基本觀念¶
在數學上,可以把數列看成一個定義在正整數上的函數:
$a_1, a_2, a_3, \dots$ 或 $a_n$。
在 Python 中,我們通常會用「列表(list)」或是「函數加迴圈」的方式來表示與產生數列。以下是一個簡單例子:
$a_n = n^2$,也就是:$1, 4, 9, 16, 25, \dots$
def square_sequence(n_max):
seq = []
for n in range(1, n_max+1):
seq.append(n**2)
return seq
square_sequence(10)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
5.2 用 Python 產生數列:基本技巧¶
我們可以用 list comprehension 更精簡地寫出同樣的數列生成方式:
[n**2 for n in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
再看一個例子:等差數列 $a_n = 2n - 1$,也就是所有奇數:$1, 3, 5, 7, 9, \dots$
[2*n - 1 for n in range(1, 11)]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
5.3 等差數列:通項與部分和¶
一個等差數列的形式為:
$a_n = a_1 + (n-1)d$,
其中 $a_1$ 為首項,$d$ 為公差。
前 $n$ 項和為:
$S_n = \dfrac{n}{2}(a_1 + a_n)$ 或 $S_n = \dfrac{n}{2}[2a_1 + (n-1)d]$。
我們可以用 Python 實驗這個公式是否正確。先用程式逐項相加:
def arithmetic_sequence(a1, d, n_max):
return [a1 + (n-1)*d for n in range(1, n_max+1)]
seq = arithmetic_sequence(a1=3, d=2, n_max=10)
seq
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
用迴圈計算前 $n$ 項和:
def partial_sum(seq, n):
return sum(seq[:n])
for n in range(1, 6):
print(f"n = {n}, S_n =", partial_sum(seq, n))
n = 1, S_n = 3 n = 2, S_n = 8 n = 3, S_n = 15 n = 4, S_n = 24 n = 5, S_n = 35
接著,用公式計算 $S_n$,檢查是否一致:
def arithmetic_sum_formula(a1, d, n):
an = a1 + (n-1)*d
return n*(a1 + an)/2
for n in range(1, 6):
s_list = partial_sum(seq, n)
s_formula = arithmetic_sum_formula(3, 2, n)
print(f"n = {n}, 列表加總 = {s_list}, 公式 S_n = {s_formula}")
n = 1, 列表加總 = 3, 公式 S_n = 3.0 n = 2, 列表加總 = 8, 公式 S_n = 8.0 n = 3, 列表加總 = 15, 公式 S_n = 15.0 n = 4, 列表加總 = 24, 公式 S_n = 24.0 n = 5, 列表加總 = 35, 公式 S_n = 35.0
5.4 等比數列:通項與部分和¶
等比數列的形式為:
$a_n = a_1 r^{n-1}$,
其中 $r$ 為公比。
若 $r \ne 1$,前 $n$ 項和為:
$S_n = a_1 \dfrac{1-r^n}{1-r}$。
我們同樣用 Python 實驗此公式,例:$a_1 = 1, r = 2$,數列為 $1, 2, 4, 8, 16, \dots$
def geometric_sequence(a1, r, n_max):
return [a1 * r**(n-1) for n in range(1, n_max+1)]
gseq = geometric_sequence(a1=1, r=2, n_max=10)
gseq
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
比較「逐項加總」與「公式」:
def geometric_sum_formula(a1, r, n):
if r == 1:
return a1 * n
return a1 * (1 - r**n) / (1 - r)
for n in range(1, 6):
s_list = sum(gseq[:n])
s_formula = geometric_sum_formula(1, 2, n)
print(f"n = {n}, 列表加總 = {s_list}, 公式 S_n = {s_formula}")
n = 1, 列表加總 = 1, 公式 S_n = 1.0 n = 2, 列表加總 = 3, 公式 S_n = 3.0 n = 3, 列表加總 = 7, 公式 S_n = 7.0 n = 4, 列表加總 = 15, 公式 S_n = 15.0 n = 5, 列表加總 = 31, 公式 S_n = 31.0
import sympy as sp
sp.init_printing()
n, a1, d, r = sp.symbols('n a1 d r', integer=True, positive=True)
n
以等差數列 $a_k = a_1 + (k-1)d$ 為例,考慮其前 $n$ 項和:
$S_n = \sum_{k=1}^n [a_1 + (k-1)d]$。
k = sp.symbols('k', integer=True, positive=True)
a_k_arith = a1 + (k-1)*d
Sn_arith = sp.summation(a_k_arith, (k, 1, n))
Sn_arith
SymPy 給出的結果就是熟悉的等差數列部分和公式。
對等比數列 $a_k = a_1 r^{k-1}$ 做類似操作:
a_k_geom = a1 * r**(k-1)
Sn_geom = sp.summation(a_k_geom, (k, 1, n))
Sn_geom
5.6 遞迴關係:用 Python 迴圈定義數列¶
很多數列不是直接給出通項公式,而是給出「前後項的關係」, 這樣的規則稱為遞迴關係(recurrence relation)。
例如費波那契數列:
$a_1 = 1, a_2 = 1, a_{n} = a_{n-1} + a_{n-2}$(對 $n \ge 3$)。
我們可以用 Python 實作:
def fibonacci(n_max):
a = {1: 1, 2: 1}
for n in range(3, n_max+1):
a[n] = a[n-1] + a[n-2]
# 回傳列表形式
return [a[n] for n in range(1, n_max+1)]
fibonacci(10)
你可以把定義換成:$a_1 = 2, a_2 = 5, a_n = a_{n-1} + a_{n-2}$,觀察數列如何改變。
5.7 用 SymPy 解線性遞迴:rsolve¶
SymPy 提供 rsolve 來處理某類型的遞迴關係(特別是線性遞迴)。
例如:
$a_n = 2a_{n-1}$,且 $a_0 = 3$。
這其實是一個等比數列,通項為 $a_n = 3\cdot 2^n$。試著用 rsolve 得到同樣結果。
from sympy import Function, rsolve
n = sp.symbols('n', integer=True)
a = Function('a')
recurrence = sp.Eq(a(n), 2*a(n-1))
initial = {a(0): 3}
solution = rsolve(recurrence, a(n), initial)
solution
再看一個稍微複雜的例子:
$a_n - 3a_{n-1} + 2a_{n-2} = 0$,且 $a_0 = 1, a_1 = 2$。
這是一個二階線性遞迴,我們用 rsolve:
a = Function('a')
recurrence2 = sp.Eq(a(n) - 3*a(n-1) + 2*a(n-2), 0)
initial2 = {a(0): 1, a(1): 2}
solution2 = rsolve(recurrence2, a(n), initial2)
solution2
你可以把這個結果展開、簡化,看看是否可以寫成某種組合形式,例如 $c_1 \cdot 2^n + c_2 \cdot 1^n$ 之類的表達方式。
5.8 啟發性例子一:存款與利息(等比數列的應用)¶
假設你把 10,000 元存入銀行,每年利率 5%(不再追加存款), 每年結算一次並複利。則第 $n$ 年末的存款金額為:
$a_n = 10000 (1.05)^{n}$。
我可以用 Python 來產生前 10 年的金額:
principal = 10000
rate = 1.05
balance = [principal * rate**n for n in range(0, 11)]
for year, money in enumerate(balance):
print(f"第 {year} 年末:{money:.2f} 元")
第 0 年末:10000.00 元 第 1 年末:10500.00 元 第 2 年末:11025.00 元 第 3 年末:11576.25 元 第 4 年末:12155.06 元 第 5 年末:12762.82 元 第 6 年末:13400.96 元 第 7 年末:14071.00 元 第 8 年末:14774.55 元 第 9 年末:15513.28 元 第 10 年末:16288.95 元
你可以思考:
- 這是一個等比數列,公比是什麼?
- 若利率改為 2%,或改成每年定期再存入固定金額,會形成什麼樣的遞迴關係?
這個例子將在機率與財務相關的課程中反覆出現。
5.9 啟發性例子二:人口成長與飽和模型(簡化版)¶
最簡單的人口成長模型是假設每年成長固定比例,形成等比數列:
$P_{n} = (1+r) P_{n-1}$。
若考慮「環境負荷上限」,可以改用較為複雜的遞迴,例如 logistic 類型:
$P_{n} = P_{n-1} + r P_{n-1}(1 - \dfrac{P_{n-1}}{K})$,
其中 $K$ 是環境承載量。雖然這個模型比較超出高中範圍,但我們可以用 Python 試著玩玩看,觀察行為:
def logistic_growth(P0, r, K, n_max):
P = [P0]
for n in range(1, n_max+1):
P_prev = P[-1]
P_new = P_prev + r * P_prev * (1 - P_prev / K)
P.append(P_new)
return P
P_values = logistic_growth(P0=10, r=0.2, K=100, n_max=20)
for n, val in enumerate(P_values):
print(f"n = {n}, P_n ≈ {val:.4f}")
n = 0, P_n ≈ 10.0000 n = 1, P_n ≈ 11.8000 n = 2, P_n ≈ 13.8815 n = 3, P_n ≈ 16.2724 n = 4, P_n ≈ 18.9973 n = 5, P_n ≈ 22.0750 n = 6, P_n ≈ 25.5154 n = 7, P_n ≈ 29.3164 n = 8, P_n ≈ 33.4608 n = 9, P_n ≈ 37.9137 n = 10, P_n ≈ 42.6215 n = 11, P_n ≈ 47.5126 n = 12, P_n ≈ 52.5003 n = 13, P_n ≈ 57.4878 n = 14, P_n ≈ 62.3756 n = 15, P_n ≈ 67.0693 n = 16, P_n ≈ 71.4866 n = 17, P_n ≈ 75.5632 n = 18, P_n ≈ 79.2563 n = 19, P_n ≈ 82.5444 n = 20, P_n ≈ 85.4261
你會看到人口一開始成長很快,之後逐漸趨近於某個穩定值,這就是「飽和效應」。
這種離散時間的遞迴關係在生態學、經濟學與社會科學中都非常重要。
5.10 啟發性例子三:誤差與收斂序列¶
考慮數列:
$e_n = \left(\dfrac{1}{2}\right)^n$。
這是一個絕對值越來越小的數列,可以想像成「誤差」隨著迭代次數而下降。 例如在某種數值方法中,每一次迭代都將誤差減半。
我們用程式觀察其行為:
e = [0.5**n for n in range(0, 11)]
for n, val in enumerate(e):
print(f"n = {n}, e_n = {val}")
n = 0, e_n = 1.0 n = 1, e_n = 0.5 n = 2, e_n = 0.25 n = 3, e_n = 0.125 n = 4, e_n = 0.0625 n = 5, e_n = 0.03125 n = 6, e_n = 0.015625 n = 7, e_n = 0.0078125 n = 8, e_n = 0.00390625 n = 9, e_n = 0.001953125 n = 10, e_n = 0.0009765625
你會發現 $e_n$ 越來越接近 0。這種數列在分析「演算法是否收斂」、「誤差是否會變小」時非常關鍵。
在後續的極限與微積分章節,我們會更正式地討論「收斂」的概念。
5.11 本章小結¶
本章你學到了:
- 如何用 Python 產生數列的前幾項,並用程式輔助觀察規律。
- 等差數列與等比數列的通項與部分和公式,並用 SymPy 驗證。
- 遞迴關係如何定義數列,如何用迴圈實作,以及用
rsolve求線性遞迴的解析解。 - 數列在現實情境中的應用:存款複利、人口成長、誤差收斂等。
請記住:
- 數列可以被看成「離散時間的函數」,與現實中的時間步驟、世代、迭代次數等概念密切相關。
- Python 與 SymPy 可以作為你的「數列實驗室」,幫助你快速測試與理解各種數列行為。
5.12 練習題¶
請在本 Notebook 中新增儲存格,試著完成以下練習:
等差數列實作
(a) 自行撰寫一個函數arith_seq(a1, d, n_max)產生前n_max項的等差數列。
(b) 使用你的函數產生 $a_1 = 5, d = -2$ 的數列,印出前 10 項。
(c) 用程式驗證部分和公式 $S_n = \dfrac{n}{2}[2a_1 + (n-1)d]$ 對這個例子是否成立。等比數列與部分和
(a) 產生 $a_1 = 3, r = \dfrac{1}{2}$ 的等比數列前 10 項。
(b) 計算前 10 項和,並與公式 $S_n = a_1 \dfrac{1-r^n}{1-r}$ 比較。
(c) 思考:當 $n$ 越來越大時,這個等比數列的部分和會趨近哪一個數?SymPy 的 summation
(a) 使用sp.summation計算 $\sum_{k=1}^n k^2$ 的公式。
(b) 試著用n=1,2,3,4,5代入檢查公式是否正確。費波那契數列
(a) 使用程式產生費波那契數列的前 15 項。
(b) 計算連續兩項的比值 $\dfrac{a_{n+1}}{a_n}$,觀察其趨勢。
(c) 查詢「黃金比例」的值,看看它與你觀察到的比值有何關係(可用 SymPy 的sp.N(sp.GoldenRatio, 10)顯示數值)。使用 rsolve 解遞迴
(a) 解遞迴關係:$a_n = 3a_{n-1} + 1$,且 $a_0 = 0$。
使用rsolve找出通項公式。
(b) 用迴圈實作這個遞迴,計算前 10 項,檢查是否與通項公式一致。存款與定期定額(應用題)
某人每年年末固定存入 5,000 元到年利率 3%(按年複利)的帳戶中,起始餘額為 0。
(a) 寫出描述此存款情形的遞迴關係式。
(b) 用 Python 實作,計算 10 年後帳戶中的金額。
(c) 試著用數學推導或 SymPy 的rsolve找出一般項公式,並檢查與程式模擬結果是否一致。加分題:收斂與發散的直觀
(a) 使用程式產生數列 $a_n = (1.1)^n$ 與 $b_n = (0.9)^n$ 的前 20 項。
(b) 觀察這兩個數列的行為:一個會越來越大,另一個會趨近 0。
(c) 用文字寫下你對「收斂」與「發散」的直觀理解。