ネヴィル、エイトケン補間は、参考程度のものです。
詳細については、Webで検索して下さい。
ネヴィル補間
ネヴィルのアルゴリズムによる補間で、ラグランジュ補間の計算のアルゴリズムの一つです。
エイトケン補間
エイトケン補間は、ラグランジェ補間、ネヴィルのアルゴリズムと似たようなものです。
ネヴィル、エイトケンとも補間の結果は、多項式補間であり、ニュートン補間と同じ結果となります。
ニュートン、ラグランジェ、ネヴィル、エイトケンの補間は、計算手順が違うだけで、同じN-1の多項式の補間計算となります。
実用的には、n次多項式近似(polynomial approximation)を使用した方が良いでしょう。
多項式近似であれば、1~(N-1)次の次数を指定して、近似の計算が可能となります。
しかし、実際のばらつきのある測定データーを使用して、補間計算をするのには無理があります。
プログラムは、ネヴィル、エイトケン、ラグランジェ補間を切り替えて計算確認出来るようになっています。
当然、計算結果は、全て同じです。
プログラム
unit Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, Vcl.StdCtrls, VCLTee.TeEngine, VCLTee.Series, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart, Vcl.Grids; type TForm1 = class(TForm) Chart1: TChart; StringGrid1: TStringGrid; NEdit: TLabeledEdit; NsetBtn: TButton; interpolationBtn: TButton; testdataBtn: TButton; XEdit: TLabeledEdit; Series1: TPointSeries; Series2: TLineSeries; Series3: TLineSeries; Series4: TLineSeries; Series5: TPointSeries; Xin_interpolation: TButton; RadioGroup2: TRadioGroup; MinxEdit: TLabeledEdit; MaxXEdit: TLabeledEdit; RadioGroup1: TRadioGroup; procedure testdataBtnClick(Sender: TObject); procedure NsetBtnClick(Sender: TObject); procedure interpolationBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Xin_interpolationClick(Sender: TObject); private { Private 宣言 } procedure GridSet(Sin, Colin: integer); procedure FGridSet(Sin, Colin: integer); // グリッドサイズ変更 public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses system.Math; type DArray = array of double; var x, y : Darray; DEF : Boolean; xmax, xmin, dx : double; // グリッドサイズの変更 procedure TForm1.GridSet(Sin, Colin: integer); // グリッドサイズ変更 var // データー行の数は10迄 H, W :integer; // それ以上はスクロールする begin if (StringGrid1.ColCount = Colin) and (StringGrid1.RowCount = Sin) then exit; StringGrid1.ColWidths[0] := 30; StringGrid1.ColCount := Colin; StringGrid1.RowCount := Sin; if Sin <= 11 then // ストリンググリッドの大きさ設定 begin // 固定行を含め11行又はそれ以下の場合 H := (StringGrid1.DefaultRowHeight + 1) * Sin; W := (StringGrid1.DefaultColWidth + 1) * (Colin - 1) + 31; StringGrid1.ScrollBars := ssNone; // スクロールバーなし end else begin // 固定行を含め11行より多い場合 H := (StringGrid1.DefaultRowHeight + 1) * (10 + 1); W := (StringGrid1.DefaultColWidth + 1) * (Colin - 1) + 31; StringGrid1.ScrollBars := ssVertical; // スクロールバー表示 end; StringGrid1.ClientWidth := W; StringGrid1.ClientHeight := H; end; // グリッド固定行の設定 procedure TForm1.FGridSet(Sin, Colin: integer); var E : integer; begin GridSet(Sin, Colin); for E := 1 to Sin - 1 do StringGrid1.Rows[E].Text := intTostr(E); StringGrid1.Cols[1].Text := 'x'; StringGrid1.Cols[2].Text := 'y'; end; // N数入力 エラー時 N < 0 function Ninput: integer; var N, ch : integer; begin result := -1; val(Form1.Nedit.Text, N, ch); if ch <> 0 then begin application.MessageBox('N数の入力に間違いが有ります。','注意',0); exit; end; if N > 100 then begin application.MessageBox('N数は100迄にして下さい。','注意',0); exit; end; if N < 3 then begin application.MessageBox('N数は3以上にして下さい。','注意',0); exit; end; result := N; end; // グリッドN数セット procedure TForm1.NsetBtnClick(Sender: TObject); var N : integer; begin N := Ninput; if N < 0 then exit; GridSet(N + 1, 3); end; // xの値チェック 同じxの値があるか確認 同じ値無 true 有り false function datacheck(x :DArray; N: integer): boolean; var i, j : integer; begin result := true; for i := 0 to N - 1 do for j := 0 to N - 1 do begin if i <> j then if x[i] - x[j] = 0 then begin application.MessageBox(pchar('x' + inttostr(i+1) + '-x' + inttostr(j+1) + 'がゼロになります。'),'注意',0); result := false; exit; end; end; for i := 0 to N - 2 do if x[i] > x[i + 1] then begin application.MessageBox(pchar('x' + inttostr(i+1) + '>x' + inttostr(i+2) + #13#10 +'値の大きさが逆です。'),'注意',0); result := false; exit; end; end; // 参考値の関数 function f(x: double):double; begin // 参考値をx^3とx^5で作成すると、補間計算がn次計算となるので誤差がでません。 result := 0; case Form1.RadioGroup2.ItemIndex of 0 : result := x - power(x,3) / 5 + power(x,5) / 100; 1 : result := ln(x); 2 : result := 1 / (1 + 2 * x * x); end; end; // 参考値 セット procedure TForm1.testdataBtnClick(Sender: TObject); var N, ch : integer; i : integer; x, y : Darray; d, dx, minx, maxx : double; begin N := Ninput; if N < 0 then exit; val(MinXedit.Text, minx, ch); if ch <> 0 then begin application.MessageBox('Min値の入力に間違いが有ります。','注意',0); exit; end; val(MaxXedit.Text, maxx, ch); if ch <> 0 then begin application.MessageBox('Max値の入力に間違いが有ります。','注意',0); exit; end; if minx >= maxx then begin application.MessageBox('Max値の値がMin値より小さな値です。','注意',0); exit; end; Nedit.Text := inttostr(N); GridSet(N + 1, 3); setlength(x, N); setlength(y, N); Series1.Clear; Series2.Clear; Series3.Clear; Series4.Clear; dx := (maxx - minx) / (N- 1); for i := Low(x) to High(x) do begin d := i * dx + minx; if radiogroup2.ItemIndex = 1 then d := d - minx + 0.1; x[i] := d; y[i] := f(d); end; for i := 0 to N - 1 do begin StringGrid1.cells[1,i + 1] := floatTostr(x[i]); StringGrid1.cells[2,i + 1] := floatTostr(y[i]); end; DEF := True; // 差分グラフ表示フラグ interpolationBtnClick(Nil); end; // ネヴィル補間計算 function neville(d: Double; x: DArray; y: DArray): Double; var w : array of array of double; i, j : integer; begin setlength(w, high(x) + 1, high(y) + 1); for i := Low(x) to High(x) do w[0,i] := y[i]; for j := 1 to High(x) do begin for i := Low(x) to (High(x) - j) do w[j,i] := w[j-1,i+1] + (w[j-1,i+1] - w[j-1,i]) * (d - x[i+j]) / (x[i+j] - x[i]); end; result := w[high(x),0]; end; // エイトケン補間計算 function aitken(d: Double; x: DArray; y: DArray): Double; var i, j : integer; w : DArray; begin setlength(w, High(x) + 1); for i := Low(x) to High(x) do w[i] := y[i]; for j := 1 to High(x) do for i := High(x) downto j do w[i] := (w[i-1] * (x[i] - d) - w[i] * (x[i-j] - d)) / (x[i] - x[i-j]); result := w[High(x)]; end; // ラグランジェ補間計算 function Lagrange( xx: double; x, y: DArray): double; var i, j : integer; s, p : double; begin s := 0; for i := Low(x) to High(x) do begin p := y[i]; for j := Low(x) to High(x) do begin if i <> j then p := p * (xx - x[j]) / (x[i] - x[j]); end; s := s + p; end; result := s; end; // グリッドの値による補間計算 procedure TForm1.interpolationBtnClick(Sender: TObject); var N, ch, i, imax : integer; cn : string; y2, y3 : double; xx : double; begin Xin_interpolation.Enabled := False; N := Ninput; if N < 0 then exit; GridSet(N + 1, 3); setlength(x, N); setlength(y, N); for i := Low(x) to High(x) do begin val(StringGrid1.cells[1,i + 1], x[i], ch); if ch <> 0 then begin cn := 'x' + intTostr(i + 1) + 'に間違いが有ります。'; application.MessageBox(pchar(cn),'注意',0); break; end; val(StringGrid1.cells[2,i + 1], y[i], ch); if ch <> 0 then begin cn := 'y' + intTostr(i + 1) + 'に間違いが有ります。'; application.MessageBox(pchar(cn),'注意',0); break; end; end; if ch <> 0 then exit; if not datacheck(x, N) then exit; // xの値に重複が無いか確認 Series1.Clear; // プロット値 Series2.Clear; // テスト計算値 Series3.Clear; // 補間値 Series4.Clear; // テスト値と補間値差分 Series5.Clear; // 指定点計算値 chart1.Title.Text.Clear; case radiogroup1.ItemIndex of 0 : chart1.Title.Text.Append('Nevilles interpolation '); 1 : chart1.Title.Text.Append('aitken interpolation'); 2 : chart1.Title.Text.Append('Lagrange interpolation'); end; xmin := x[0]; xmax := x[0]; for i := Low(x) to High(x) do begin if x[i] > xmax then xmax := x[i]; if x[i] < xmin then xmin := x[i]; Series1.AddXY(x[i], y[i]); end; imax := (N - 1) * 20; // 分割数 dx := (xmax - xmin) / imax; y3 := 0; for i := 0 to imax do begin xx := i * dx + x[0]; case radiogroup1.ItemIndex of 0 : y3 := neville(xx, x, y); 1 : y3 := aitken(xx, x, y); 2 : y3 := Lagrange(xx, x, y); end; Series3.AddXY(xx, y3); if DEF then begin if radiogroup2.ItemIndex = 1 then xx := xx - xmin + 0.1; y2 := f(xx); Series2.AddXY(xx, y2); // テスト値 Series4.AddXY(xx, y3 - y2); // 差分値 差分値-テスト値 end; end; DEF := False; Xin_interpolation.Enabled := True; end; // 指定値からの計算 指定値xによるy補間値計算とグラフ表示 procedure TForm1.Xin_interpolationClick(Sender: TObject); var ch, i, j : integer; xd, y1, y3, xx, gmin, gmax: double; begin val(Xedit.Text, xd, ch); if ch <> 0 then begin application.MessageBox('xからY推定の入力に間違いが有ります。','注意',0); exit; end; Series2.Clear; // テスト値グラフ Series3.Clear; // 補間値グラフ Series4.Clear; // 差分値 Series5.Clear; // 指定値点 chart1.Title.Text.Clear; case radiogroup1.ItemIndex of 0 : chart1.Title.Text.Append('Nevilles interpolation '); 1 : chart1.Title.Text.Append('aitken interpolation'); 2 : chart1.Title.Text.Append('Lagrange interpolation'); end; gmin := xmin; gmax := xmax; if xd < gmin then gmin := xd; if xd > gmax then gmax := xd; // 最小最大区間グラフ再描画 i := round((gmax - gmin) / dx); y3 := 0; for j := 0 to i do begin xx := j * dx + gmin; case radiogroup1.ItemIndex of 0 : y3 := neville(xx, x, y); 1 : y3 := aitken(xx, x, y); 2 : y3 := Lagrange(xx, x, y); end; Series3.AddXY(xx, y3); end; // 指定値点グラフ追加 指定値xによるy補間値計算とグラフ表示 y1 := 0; case radiogroup1.ItemIndex of 0 : y1 := neville(xd, x, y); 1 : y1 := aitken(xd, x, y); 2 : y1 := Lagrange(xd, x, y); end; Series5.AddXY(xd, y1); end; // グリッド初期設定 procedure TForm1.FormCreate(Sender: TObject); begin FGridSet(101, 3); // 固定行1列1 + 100行2列まで行列を変更しても // 入力値がクリアされないようにします。 GridSet(4, 3); // 最初の設定 end; end.
Nevilles_algorithm.zip
三角関数、逆三角関数、その他関数 に戻る