第1種球ベッセル関数
ベッセル関数の詳細については、Webで検索して参照してください。
左図は第1種の球ベッセル関数の計算式ですが、第1種ベッセル関数の実数計算により簡単に求めることが出来ます。
第1種ベッセル関数の計算については、第1種ベッセル関数を参照すれば分かります。
次の図は、プログラムの実行画面です。
Xの値が大きくなると、計算の有効桁数の関係で、誤差が大きくなるのは第1種ベッセル関数と変わりません。
あまり大きな値を与えると、誤差の方が大きくなります。
プログラム
// Xの値 積分計算の上限値MNによってオーバーフローを発生するので // コンパイル設定にオーバーフローチックが必須です。 // Xの値が大きくなると誤差が大きくなります 演算の有効桁数不足 unit Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, VclTee.TeeGDIPlus, VCLTee.TeEngine, VCLTee.Series, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart, system.UITypes; type TForm1 = class(TForm) Button1: TButton; Chart1: TChart; Series1: TLineSeries; LabeledEdit2: TLabeledEdit; Series2: TPointSeries; LabeledEdit1: TLabeledEdit; Memo1: TMemo; CheckBox1: TCheckBox; CheckBox2: TCheckBox; Button2: TButton; procedure Button1Click(Sender: TObject); private { Private 宣言 } procedure Besselgraph(v, Xmax: extended; flag: boolean); function BesselG(X: extended; v: extended; flag: boolean): extended; function Log_Gamma(x: extended): extended; function Gamma(x: extended): extended; // ガンマ関数 function Jvx(v, x: extended; flag: boolean): extended; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses system.math; const // 誤差計算用データー j0x: array[0..10] of extended = ( 1, 0.8414709848078965066525, 0.454648713412840847698, 0.04704000268662240736691, -0.1892006238269820628432, -0.1917848549326276937786, -0.04656924969982097880193, 0.09385522838839844148529, 0.123669780827922722226, 0.04579094280463961886161, -0.05440211108893698134047 ); i0x: array[0..10] of extended = ( maxextended, 1.175201193643801456882, 1.813430203923509383834, 3.339291642469967299658, 6.822479299281938112227, 14.8406421155577517954, 33.6188595617132046875, 78.33087475332093176768, 186.3098532236937732645, 450.1713224536433289461, 1101.323287470339337724 ); //ベルヌーイ数B(2)、B(4)、B(6)、...、B(20) B : array[1..10] of extended = ( 1.0 / 6, // B(2) -1.0 / 30, 1.0 / 42, -1.0 / 30, 5.0 / 66, -691.0 / 2730, 7.0 / 6, -3617.0 / 510, 43867.0 / 798, -174611.0 / 330); // B(20) m: integer = sizeof(B) div sizeof(extended); //------------------------------------------------------------------------------ // ガンマ関数 function TForm1.Log_Gamma(x: extended): extended; var i : integer; sum : extended; xx, v : extended; ln_sqrt_2pi: extended; begin ln_sqrt_2pi := ln(sqrt(2 * pi)); // = ln(2 * pi) / 2; sum := 0; v := 1; while x < m do begin v := v * x; x := x + 1; end; xx := 1 / (x * x); for i := m downto 2 do sum := (sum + B[i] / (i * 2 * (2 * i - 1))) * xx; result := (sum + B[1] / 2) / x + ln_sqrt_2pi - ln(v) - x + (x - 0.5) * ln(x); end; function TForm1.Gamma(x: extended): extended; // ガンマ関数 begin if x < 0 then begin result := pi / (sin(pi * x) * exp(log_Gamma(1 - x))); end else begin result := exp(Log_Gamma(x)); end; end; //----------------------- new -------------------------------------------------- // X 値 // v 次数 // flag false 通常 true 変形 function TForm1.Jvx(v, x: extended; flag: boolean): extended; var k : integer; g, j, bkk, n: extended; function Bk(k : integer): extended; var kn : integer; Bn, Y, Zk: extended; begin Y := -(x / 2) * (x / 2); if flag then Y := -Y; Bn := 1; for kn := 1 to k do begin Zk := Y / (kn * (kn + v)); Bn := Zk * Bn; end; result := Bn end; begin n := round(v); if (n = v) and (n < 0) then v := abs(v); g := gamma(1 + v); bkk := 0; for k := 0 to 100 do bkk := bkk + Bk(k); j := power(x / 2, v) / g * bkk; if (not flag) and (abs(n) = v) and (n < 0) then j := j * Power(-1, v); result := j; end; //----------------------------------------------------------------------------- // 第1種ベッセル関数 Γ関数使用 // X 値 // v 次数 // flag false 通常 true 変形 function TForm1.BesselG(X: extended; v: extended; flag: boolean): extended; const Mn = 50; var M : Integer; B, S, n: extended; begin n := round(v); if (n = v) and (n < 0) then v := abs(v); S := 0; for M := 0 to MN do begin B := 1 / Gamma(M + 1) / Gamma(M + v + 1); // B = 1 / (Γ(m + 1)Γ(m + n + 1)) if not flag then S := S + power(-1, M) * B * power(X / 2, 2 * M + v) else S := S + B * power(X / 2, 2 * M + v) end; if (not flag) and (abs(n) = v) and (n < 0) then S := S * Power(-1, v); result := S; end; // 第1種球ベッセル関数 グラフ表示 // v 次数 // Xmax グラフ最大値 // flag false 通常 true 変形 procedure TForm1.Besselgraph(v, Xmax: extended; flag: boolean); const NMAX = 10000; var Y, X: extended; I : integer; XMIN: extended; begin XMIN := 0; x := 0; if v = 0 then Y := 1 else Y := 0; Series1.AddXY(X, Y); for I := 1 to NMAX - 1 do begin X := XMIN + (XMAX - XMIN) * I / NMAX; Y := sqrt(pi/(2 * X)) * BesselG(X, v + 0.5, flag) Series1.AddXY(X, Y); end; end; // ベッセル球関数計算 procedure TForm1.Button1Click(Sender: TObject); var ch: integer; X, Y, v, vs2 : extended; Flg: boolean; begin val(LabeledEdit1.Text, v, Ch); if ch <> 0 then begin MessageDlg('次数vに間違いがあります。', mtInformation, [mbOk], 0, mbOk); exit; end; val(LabeledEdit2.Text, X, Ch); if ch <> 0 then begin MessageDlg('X値に間違いがあります。', mtInformation, [mbOk], 0, mbOk); exit; end; vs2 := 1 / 2; Series1.Clear; Series2.Clear; chart1.LeftAxis.AutomaticMaximum := False; chart1.LeftAxis.AutomaticMinimum := False; memo1.Clear; Chart1.Title.Text.Clear; chart1.LeftAxis.Title.Caption := ''; if checkbox1.Checked = False then begin Flg := False; if x = 0 then begin if v = 0 then Y := 1 else Y := 0; end else if checkbox2.Checked = false then Y := sqrt(pi/(2 * X)) * Jvx(v + vs2, X , Flg) else Y := sqrt(pi/(2 * X)) * BesselG(X, v + vs2, Flg); if Chart1.LeftAxis.Maximum <= Y + 2 then begin Chart1.LeftAxis.Maximum := Y + 2; Chart1.LeftAxis.Minimum := Y - 2; end else begin Chart1.LeftAxis.Minimum := Y - 2; Chart1.LeftAxis.Maximum := Y + 2; end; Series2.AddXY(X, Y); Chart1.Title.Text.Append('第1種球ベッセル関数'); Besselgraph(v, 10, Flg); memo1.Lines.Add('第1種球ベッセル関数'); memo1.Lines.Add('jvx = ' + floatTostr(Y)); end else begin Flg := True; if X = 0 then begin if v = 0 then Y := 1 else Y := 0; end else if checkbox2.Checked = false then Y := sqrt(pi/(2 * X)) * Jvx(v + vs2, X , Flg) else Y := sqrt(pi/(2 * X)) * BesselG(X, v + vs2, Flg); if Chart1.LeftAxis.Maximum <= Y + 2 then begin Chart1.LeftAxis.Maximum := Y + 2; Chart1.LeftAxis.Minimum := Y - 2; end else begin Chart1.LeftAxis.Minimum := Y - 2; Chart1.LeftAxis.Maximum := Y + 2; end; Series2.AddXY(X, Y); Chart1.Title.Text.Append('第1種変形球ベッセル関数'); Besselgraph(v, 5, Flg); memo1.Lines.Add('第1種変形球ベッセル関数'); memo1.Lines.Add('ivx = ' + floatTostr(Y)); end; end; // 計算誤差の確認 procedure TForm1.Button2Click(Sender: TObject); var flg: boolean; i, p, l: integer; jk, vs2: extended; def : extended; defs, re, ex, ads, no : string; begin memo1.Clear; Series1.Clear; Series2.Clear; chart1.LeftAxis.AutomaticMaximum := True; chart1.LeftAxis.AutomaticMinimum := True; {$IFDEF CPUX64} chart1.LeftAxis.Title.Caption := 'xxE14'; Memo1.Lines.Append('X64 extended'); {$ELSE} chart1.LeftAxis.Title.Caption := 'xxE15'; Memo1.Lines.Append('X86 extended'); {$ENDIF} flg := False; vs2 := 1 / 2; if checkbox1.Checked = true then flg := true; for i := 0 to 10 do begin if i = 0 then begin if flg then jk := 0 else jk := 1; end else if checkbox2.Checked = false then jk := sqrt(pi/(2 * i)) * Jvx(0 + vs2, i, flg) else jk := sqrt(pi/(2 * i)) * BesselG(i, 0 + vs2, flg); if flg and (i = 0) then def := 0 else begin if flg then def := abs(i0x[i] - jk) else def := abs(j0x[i] - jk); end; {$IFDEF CPUX64} Series1.AddXY(i, def * 1E14); {$ELSE} Series1.AddXY(i, def * 1E15); {$ENDIF} if def <> 0 then defs := floatTostr(def) else defs := ' 0'; l := length(defs); p := pos('E', defs, 1); re := copy(defs, 0, 4); ex := copy(defs, p, l - p + 1); no := inttostr(i); if i < 10 then no := ' ' + no; if i mod 2 = 0 then ads := no + ' ' + re + ex else begin ads := ads + ' ' + no + ' ' + re + ex; memo1.Lines.Append(ads); end; if i = 10 then memo1.Lines.Append(ads); end; end; end.