Pet*_*rSM 4 c++ math numerical-methods runge-kutta
下面是我的四阶Runge-Kutta算法,用于求解一阶ODE。我对照此处找到的Wikipedia示例进行检查以解决:
\frac{dx}{dt} = tan(x) + 1
Run Code Online (Sandbox Code Playgroud)
不幸的是一点点。我玩了很长时间,但找不到错误。答案应该是t = 1.1和x = 1.33786352224364362。以下代码给出了t = 1.1和x = 1.42223。
/*
This code is a 1D classical Runge-Kutta method. Compare to the Wikipedia page.
*/
#include <math.h>
#include <iostream>
#include <iomanip>
double x,t,K,K1,K2,K3,K4;
const double sixth = 1.0 / 6.0;
static double dx_dt(double t, double x){
return tan(x) + 1;
}
int main(int argc, const char * argv[]) {
/*======================================================================*/
/*===================== Runge-Kutta Method for ODE =====================*/
/*======================================================================*/
double t_initial = 1.0;// initial time
double x_initial = 1.0;// initial x position
double t_final = 1.1;// value of t wish to know x
double dt = 0.025;// time interval for updates
double halfdt = 0.5*dt;
/*======================================================================*/
while(t_initial < t_final){
/*============================ Runge-Kutta increments =================================*/
double K1 = dt*dx_dt( t_initial, x_initial );
double K2 = dt*dx_dt( t_initial + halfdt, x_initial + halfdt*K1 );
double K3 = dt*dx_dt( t_initial + halfdt, x_initial + halfdt*K2 );
double K4 = dt*dx_dt( t_initial + dt, x_initial + dt*K3 );
x_initial += sixth*(K1 + 2*(K2 + K3) + K4);
/*============================ prints =================================*/
std::cout << t_initial << std::setw(16) << x_initial << "\n";
/*============================ re-setting update conditions =================================*/
t_initial += dt;
/*======================================================================*/
}
std::cout<<"----------------------------------------------\n";
std::cout << "t = "<< t_initial << ", x = "<< x_initial << std::endl;
}/* main */
Run Code Online (Sandbox Code Playgroud)
问题在于,用于代码的表与您在维基百科中引用的表的表不同。您正在使用的是这样的:
0 |
1/2 | 1/2
1/2 | 0 1/2
1 | 0 0 1
-------------------------------------
| 1/6 1/3 1/3 1/6
Run Code Online (Sandbox Code Playgroud)
维基百科中使用的是
0 |
2/3 | 2/3
---------------------
| 1/4 3/4
Run Code Online (Sandbox Code Playgroud)
根据步长大小,不同的表格会产生不同的结果,这是用于确保步长大小足以满足一定精度的方法。但是,当时dt -> 0
,所有表格都是相同的。
除此之外,即使对于RK4,您的代码仍然是错误的。该函数的第二部分应减半,而不是0.5*dt
:
double K1 = dt*dx_dt( t_initial, x_initial );
double K2 = dt*dx_dt( t_initial + halfdt, x_initial + 0.5*K1 );
double K3 = dt*dx_dt( t_initial + halfdt, x_initial + 0.5*K2 );
double K4 = dt*dx_dt( t_initial + dt, x_initial + K3 );
Run Code Online (Sandbox Code Playgroud)