python中的Runge Kutta 4

python中的Runge Kutta 4,python,runge-kutta,Python,Runge Kutta,我有一个问题,在代码中,h=0.1显示了一个小错误,h=0.01和h=0.001。我不明白为什么?但当h=0.0001时,误差再次减小 谢谢 def f(x,y): return 2*x**2-4*x+y def RK4(x0,y0): while x0 < b: k1 = h*f(x0,y0) k2 = h*f(x0+0.5*h,y0+0.5*k1) k3 = h*f(x0+0.5*h,y0+0.5*k2)

我有一个问题,在代码中,h=0.1显示了一个小错误,h=0.01和h=0.001。我不明白为什么?但当h=0.0001时,误差再次减小

谢谢

def f(x,y):
    return 2*x**2-4*x+y

def RK4(x0,y0):
    while x0 < b:
        k1 = h*f(x0,y0)
        k2 = h*f(x0+0.5*h,y0+0.5*k1)
        k3 = h*f(x0+0.5*h,y0+0.5*k2)
        k4 = h*f(x0+h,y0+k3)
        y0+=(k1+2*k2+2*k3+k4)/6
        x0+=h
    return y0

b=3
h=0.001
print(RK4(1,0.7182818))
定义f(x,y): 返回2*x**2-4*x+y def RK4(x0,y0): 而x0错误分析 如果您还打印最后一个
x0
,那么您将看到迭代从未在
b
处停止过。
h
的浮点表示将被机器epsilon的一部分关闭。如果它稍微大一点,那么迭代将执行正确数量的循环。如果较小,则迭代将执行一个超出必要的循环,并在略小于
b+h
的位置停止

此外,该测试问题的线性DE具有易于计算的精确解

y' - y = f'(x) - f(x),  f(x) = -2*x^2
=> (y(x)-f(x))*exp(-x) = (y0-f(x0))*exp(-x0)
所以解的流函数是

def phi(x, x0,y0): return (y0+2*x0**2)*np.exp(x-x0)-2*x**2
为原始代码提供结果

exact solution: 2.085536712902183

 h           returned   x       returned   y      to exact at b  to exact at ret. x
------------------------------------------------------------------------------------
   0.1 : 3.00000000000000178  2.08553122271193736  -5.49019e-06 -5.49019e-06
  0.01 : 3.00999999999997936  2.16719971215161866      0.081663 -6.90252e-10
 0.001 : 3.00099999999977962  2.09363029572970216    0.00809358 -3.81029e-13
0.0001 : 3.00000000000200018  2.08553671291035991   8.17701e-12 -7.99849e-12
 1e-05 : 3.00000000001310241  2.08553671302741339    1.2523e-10  1.92886e-11
在超调情况下,误差明显小于
h
,而其他行显示预期的4阶收敛与浮点误差累积相竞争

修正变量 您可以通过预先计算步骤数或更正最后一步来更正此问题

def f(x,y):
    return 2*x**2-4*x+y

def RK4(x0,y0,xf,h):
    while x0 < xf:
        if x0+h > xf: h=xf-x0
        k1 = h*f(x0,y0)
        k2 = h*f(x0+0.5*h,y0+0.5*k1)
        k3 = h*f(x0+0.5*h,y0+0.5*k2)
        k4 = h*f(x0+h,y0+k3)
        y0+=(k1+2*k2+2*k3+k4)/6
        x0+=h
    return x0,y0

b=3
for k in range (1,5): 
    h0=10**-k; 
    for h in [2*h0, h0, 0.5*h0]:
        xf,yf = RK4(x0, y0,b,h); 
        print(f'{h:6} : {xf:.17f}  {yf:.17f}  {yf-phi(b,x0,y0):12.6g}  {(yf-phi(b,x0,y0))/h**4:12.6g}')
计算的误差系数表明,对于
0.005
0.1
之间的
h
,四阶方法误差占主导地位,对于较大的步长,高阶误差项太大,对于较低的
h
而言,必要步骤的数量增加得如此之多,以至于浮点误差的累积在方法误差中占主导地位


如前所述,您可以预先计算步骤的数量,并确保
N*h=xf-x0
。为了那个替代品

    while x0 < xf:
        if x0+h > xf: h=xf-x0
您仍然可以在
x0
中观察浮点错误的累积

0.1     (3.0000000000000018, 2.0855312227119374)
0.01    (2.9999999999999796, 2.0855367122311055)
0.001   (2.9999999999997797, 2.085536712900021 )
0.0001  (3.000000000002,     2.08553671291036  )
1e-05   (3.0000000000131024, 2.0855367130274134)

如果我正确地假设您的代码生成的结果接近预期结果,那么您就没有编程问题,而是数值问题。这是一个更适合我的东西。然而,如果你问,请详细说明:你期望什么,为什么?你得到的实际值是多少?
    Dx = float(xf-x0); N = int(0.5+Dx/h); h = Dx/N
    for _ in range(N):
0.1     (3.0000000000000018, 2.0855312227119374)
0.01    (2.9999999999999796, 2.0855367122311055)
0.001   (2.9999999999997797, 2.085536712900021 )
0.0001  (3.000000000002,     2.08553671291036  )
1e-05   (3.0000000000131024, 2.0855367130274134)