C 语言复合数列递推¶
一段简短的 C 代码,模拟两个相互影响的序列递推过程。初始值各为 100,每轮按固定比例从对方序列中吸收一部分,迭代 100 轮后收敛至稳定比例。
原始代码¶
#include <stdio.h>
int main()
{
int len = 100;
float a[len], b[len];
a[0] = 100, b[0] = 100;
for (int i = 1; i < len; i++)
{
a[i] = 0.9 * a[i - 1] + 0.15 * b[i - 1];
b[i] = 0.85 * b[i - 1] + 0.1 * a[i - 1];
printf("%lf %lf\n", a[i], b[i]);
}
return 0;
}
问题¶
变长数组¶
int len = 100; float a[len]; 用的是 C99 的变长数组(VLA)。MSVC 不支持 VLA,代码在 Visual Studio 下无法编译。应改用 #define 或 const。
float 精度¶
连续 100 次浮点迭代,float 的 6~7 位有效数字在后半程会积累误差。用 double 更可靠。
仅输出数值,缺少分析¶
程序忠实地算出了每一轮的值,但没有说明这个系统在做什么、最终会收敛到哪里。
数学分析¶
将递推写成矩阵形式:
\[
\begin{bmatrix} a_i \\ b_i \end{bmatrix} =
\begin{bmatrix} 0.9 & 0.15 \\ 0.1 & 0.85 \end{bmatrix}
\begin{bmatrix} a_{i-1} \\ b_{i-1} \end{bmatrix}
\]
提取两个信息:
总量守恒。每轮 a 流失 10% 到 b、b 流失 15% 到 a,但恰好:
\[
a_i + b_i = (0.9+0.1)a_{i-1} + (0.15+0.85)b_{i-1} = a_{i-1} + b_{i-1} = 200
\]
总量始终锁定在 200。
特征值与稳态。转移矩阵的特征方程为:
\[
\lambda^2 - 1.75\lambda + 0.75 = 0
\]
解得 \(\lambda_1 = 1.0\),\(\lambda_2 = 0.75\)。对应 \(\lambda_1=1\) 的特征向量满足 \(a = 1.5b\),即 a 与 b 的比例收敛至 3:2。结合总量 200,稳态值:
\[
a_{\infty} = \frac{3}{5} \times 200 = 120,\qquad b_{\infty} = \frac{2}{5} \times 200 = 80
\]
修正后代码¶
#include <stdio.h>
#define LEN 100 // 修正:用宏替代 VLA
int main()
{
double a[LEN], b[LEN]; // 修正:double 替代 float
a[0] = 100, b[0] = 100;
printf("轮次 a b\n");
for (int i = 1; i < LEN; i++)
{
a[i] = 0.9 * a[i - 1] + 0.15 * b[i - 1];
b[i] = 0.85 * b[i - 1] + 0.1 * a[i - 1];
printf("%3d %8.4lf %8.4lf\n", i, a[i], b[i]); // 修正:格式控制
}
printf("\n理论稳态: a = 120.0, b = 80.0\n");
return 0;
}
运行前 10 轮输出:
轮次 a b
1 105.0000 95.0000
2 108.7500 91.2500
3 111.5625 88.4375
4 113.6719 86.3281
5 115.2539 84.7461
6 116.4404 83.5596
7 117.3303 82.6697
8 117.9977 82.0023
9 118.4983 81.5017
10 118.8737 81.1263
a 从 100 单调上升趋近 120,b 从 100 单调下降趋近 80。到第 40 轮左右,两者距离稳态已不足 0.01。