簡體   English   中英

Python 中的 Runge-Kutta 4

[英]Runge-Kutta 4 in python

我有一個問題,在代碼中,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))

錯誤分析

如果您還打印最后一個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}')

這給出了預期的結果

 h          returned  x               y               error          error/h^4
--------------------------------------------------------------------------------
   0.2 : 3.00000000000000000  2.08546790477393795  -6.88081e-05    -0.0430051
   0.1 : 3.00000000000000000  2.08553122271192359  -5.49019e-06    -0.0549019
  0.05 : 3.00000000000000000  2.08553632856235494   -3.8434e-07    -0.0614944
  0.02 : 3.00000000000000000  2.08553670239502909  -1.05072e-08    -0.0656697
  0.01 : 3.00000000000000000  2.08553671223127068  -6.70912e-10    -0.0670912
 0.005 : 3.00000000000000000  2.08553671285973685   -4.2446e-11    -0.0679137
 0.002 : 3.00000000000000000  2.08553671290148124  -7.01661e-13    -0.0438538
 0.001 : 3.00000000000000000  2.08553671290180187  -3.81029e-13     -0.381029
0.0005 : 3.00000000000000000  2.08553671290032216  -1.86073e-12      -29.7717
0.0002 : 3.00000000000000000  2.08553671290186093  -3.21965e-13      -201.228
0.0001 : 3.00000000000000000  2.08553671289418929  -7.99361e-12      -79936.1
 5e-05 : 3.00000000000000000  2.08553671292377762   2.15947e-11   3.45516e+06

計算的誤差系數表明,4階方法誤差在0.0050.1之間的h占主導地位,對於較大的步長,較高的階誤差項太大,對於較小的h ,所需的步數增加了很多,以至於浮點數的累積錯誤支配了方法錯誤。


如前所述,您可以預先計算步驟數N並確保N*h=xf-x0 對於那個替換

    while x0 < xf:
        if x0+h > xf: h=xf-x0

    Dx = float(xf-x0); N = int(0.5+Dx/h); h = Dx/N
    for _ in range(N):

您仍然可以觀察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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM