by Conmajia
2014
原文写于 2014 年 ,用 C# 完成 ,现在改为 JavaScript. 欧拉和中心差分逼近 ,是最朴素的想法 ,但代数精度太低 ,而龙格库塔的稳定性又是个问题. 总之只能用来计算普通的东西 ,高大上问题一般还是使用广义 α ,Wilson-Θ 之类的 ,利用系数调节人工阻尼 ,让低频的部分少受算法影响 ,高频阻尼增大 ,增加微分方程的稳定性 ,又不影响算法的精度.
当然 ,现在大把的 lib 、app ,你完全可以用 py 、mtlb 之类的搞定 ,不需要搞懂任何原理.
Math.NET 计划是用于.NET 的数学运算库 ,包括了数值计算库 Iridium.NET ,非常经典 (且古老) .
工程中有时候需要解微分方程 ,比如这种:
y′=y−2xy
y(0)=1. 两边积分 ,得到:
∫xn+1xny′dx=∫xn+1xn(y−2xy)dxyn+1−yn=∫xn+1xn(y−2xy)dxy=√1+2x
工程上一般不需要精确解 ,求个数值就好 ,通常采用差分近似代替微分 ,最简单最朴素的办法是:
yn+1=yn+Δxf(xn,yn)n=0,1,2,⋯(1)
推导很简单 ,对 xn ,有:
y′n=f(xn,yn).
对 y′(xn) 有:
y′n≈yn+1−ynΔx.(2)
(2) 的左边叫微商 ,右边叫差商 ,Δx=|xn+1−xn|.
代回 (2) ,有:
y′n=f(xn,yn)⇒yn+1−ynΔx≈f(xn,yn)yn+1−yn≈Δxf(xn,yn)yn+1≈y(xn)+Δxf(xn,yn).
于是 ,(1) 成了:
yn+1=yn+Δx(yn−2xnyn).(3)
用 myFn
函数表示余项 yn−2xnyn:
function myFn(x, y) {
return y - 2 * x / y;
}
Euler 可以这样实现:
function calculate(x0, y0, delta, xn) {
var yn;
while(x0 < xn) {
yn = y0 + delta * myFn(x0, y0);
y0 = yn;
x0 = x0 + delta;
}
return yn;
}
现在可以开始试验. 理论上:
y=√1+2x⇒y(1)=√3≈1.7321
√3 是方程的精确解 ,程序的目标是通过计算 ,得到尽量接近精确解的结果.
取 x0=0 ,y0=1 ,Δx=0.1 ,程序计算结果为:
ans = 1.784771
误差 ε1=3.04%. 现在减小 Δx ,比如 Δx=0.0001 ,计算结果为:
ans = 1.732112
ε2=0.0007% ,比较接近真值了.
尽管这个方法可以求到比较精确的解 ,但是 Δx 太小的话 ,显然 while
会执行很多次 Nwhile\prop1Δx ,效率低下.
引入定积分的梯形公式:
∫xn+1xnf(x,y)dx≈Δx2[f(xn,yn)+f(xn+1,yn+1)]
(3) 可以写成:
yn+1≈yn+Δx2[f(xn,yn)+f(xn+1,yn+1)].(4)
(3) 和 (4) 的特点是 ,前者速度快 ,精度低; 后者速度慢 ,精度高. 所以对于粗算 ,可以使用:
y′n+1=yn+Δxf(xn,yn)
精算 ,可以用:
yn+1=yn+Δx2[f(xn,yn)+f(xn+1,y′n+1)].
结合起来 ,先通过粗算得到 y′n+1 的近似值 ,再进行精算 ,得到高精度的最终解. 这是一个比较均衡的折衷 ,既保证了计算结果的准确度 ,又保证了计算效率. 下面是改进后的代码:
function calculate(x0, y0, delta, xn) {
var yp, yc;
while(x0 < xn) {
yp = y0 + delta * myFn(x0, y0);
yc = y0 + delta * myFn(x0 + delta, yp);
y0 = 1 / 2 * (yp + yc);
x0 = x0 + delta;
}
return y0;
}
取 x0=0 ,y0=1 ,Δx=0.1:
ans = 1.737867
ε3=0.33%.
和 ε1 相比 ,在 Δx 相同——意味着执行时间相近——的情况下 ,精度提高了 10 倍.
手工求微分方程基本是这么个思路. 当然 ,更多的时候 ,做个伸手党其实很不错的 ,大把的现成玩意儿可以用 ,我干嘛还要费那劲呢?
The End. □
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2018-02-21 命令行程序增加 GUI 外壳
2018-02-21 🖥️ 自制虚拟机 - 概念和汇编器
2017-02-21 字符型液晶屏模拟控件(En)