カールソンの楕円積分複素数計算
RC,RF,RJの複素数計算プログラムを作成したので、楕円積分 離心率(K)、積分範囲(X)指定のプログラムを作成しました。
積分範囲XはX=sin(Φ)の範囲です。
角度は、Φ=sin-1(X)で、Xの値に1以上を指定すると、1迄の値として実数部の値がπ/2となり、1を超えた部分が虚数-Φ’iの値となります。
いくら大きな値を指定しても1の値を超えた部分は、虚数になります。
左図のプログラムでは、積分範囲の指定に角度が有りますが、実数部の角度は90°迄で、実数部に90°を指定した時のみ、虚数部の角度が指定できます。
虚数部の角度値はマイナスの値を指定します。
sin(Φ)の計算をすると、積分範囲X必ず実数のみの値となり虚数はゼロになります。
積分範囲Xの値に1以上を或いは、離心率の値に1以上を指定すると、楕円積分結果に虚数部が現れますが、RF、RJの引数に虚数部の値は有りません。
離心率kの値に1以上を指定した場合は、実際の実数の積分範囲は90°以下になります。
第三種楕円積分の特性値(a)或いは、パラメータ(m)の値に関しては複素数の入力が出来るようにしても、その計算結果がどの様な意味をもっているのか解らないのと、検算も出来ないので、実数のみの入力になっています。
ランデン変換の複素数計算第一二種のランデン変換楕円積分の積分範囲指定の角度は、90°を超えた場合、90°分割の計算になっています。
ランデン変換の複素数計算と値が一致するのは、積分範囲Xの値が1(sin90°)迄です。
又、ランデン変換では、離心率kの値に1を越えてランデン変換することが出来ないので、1より大きい場合は、1より小さくなるように変換をして計算していますし、負数の場合は、正の値で1以下になる様に変換して計算していますが、カールソンので楕円積分では、その必要性はありません。
高精度計算サイトのフリー計算に、ここのカールソンの複素数のプログラムと同じ計算があるのですが、離心率kの値によっては、積分範囲Xの値が1.2辺りを越えると計算結果の値があわなくなります、原因は判りませんプログラムにミスは無いと思うのですが。
プログラム(Variant変数使用)
離心率 k = 1
で89.9997°範囲Xの値は0.999999999986292で、 第三種の特性値 a=1の時、積分角度89.8°でこの時の範囲Xの値は0.99999390765779でゼロでの除算が発生します。
あきらかに、演算の有効桁数が不足しています。
// 1/31/2021 // プログラムは https://arxiv.org/abs/math/9409227 のレポートを元に作成しています // 離心率k= 1 角度φ=89.9999°近辺でゼロでの除算と桁落ちが発生します // 係数a= 1 角度φ=89.8°近辺でゼロでの除算と桁落ちが発生します unit Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons; type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; LabeledEdit1: TLabeledEdit; LabeledEdit2: TLabeledEdit; LabeledEdit3: TLabeledEdit; Button1: TButton; Button2: TButton; LabeledEdit4: TLabeledEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; Edit6: TEdit; Label2: TLabel; Label3: TLabel; Memo1: TMemo; LabeledEdit5: TLabeledEdit; LabeledEdit6: TLabeledEdit; RadioButton1: TRadioButton; RadioButton2: TRadioButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private 宣言 } function datainput(var a, x, k: double; var FI: boolean): boolean; procedure calc_Third_elliptic_integral_complex; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses system.Math, System.VarCmplx; var ERRF : integer; ZeroF : integer; // 複素数の生成 function Vc(a, b: double): Variant; begin result := varascomplex(result); result.real := a; result.Imaginary := b; end; // ---------------- RC --------------------------------------------------------- function RCC(x, y: variant): variant; label Ext; const r = 1E-24; c1 = 3 / 10; c2 = 1 / 7; c3 = 3 / 8; c4 = 9 / 22; c5 = 159 / 208; c6 = 9 / 8; var xt, yt, w, yb : variant; lamda, A0, Q : variant; s, Am : variant; m : integer; pt : double; begin if Varcomplexabs(y) = 0 then begin // m := 0; result := Vc(0, 0); ZeroF := ZeroF or 1; goto Ext; end; if (y.real > 0) or (y.Imaginary <> 0) then begin xt := x; yt := y; w := Vc(1, 0); end else begin xt := x - y; yt := - y; pt := xt.real * xt.real + xt.Imaginary * xt.Imaginary; if pt < 1E-5 then begin // 演算エラー回避 if xt.real > 0 then xt := Vc(1E-5, 0) else xt := Vc(-1E-5, 0); ERRF := ERRF or 1; end; w := Varcomplexsqrt(x / xt); end; yb := yt; A0 := (xt + yt + yt) / 3; Am := A0; Q := power(3 * r, -1 / 8) * Varcomplexabs(A0 - xt); m := 0; repeat lamda := 2 * Varcomplexsqrt(xt) * Varcomplexsqrt(yt) + yt; xt := (xt + lamda) / 4; yt := (yt + lamda) / 4; Am := (Am + lamda) / 4; m := m + 1; until (power(4, -m) * Q < Varcomplexabs(Am)) or (m > 10); pt := am.real * am.real + am.Imaginary * am.Imaginary; if pt < 1E-5 then begin // 演算エラー回避 if am.real > 0 then am := Vc(1E-5, 0) else am := Vc(-1E-5, 0); ERRF := ERRF or 1; end; s := (yb - A0) / Varcomplexpower(4, m) / Am; result := w * (1 + s * s * (c1 + s * (c2 + s * (c3 + s * (c4 + s * (c5 + s * c6)))))) / Varcomplexsqrt(Am); Ext: // Form1.Memo1.Lines.Append('RC Loop数 = ' + intTostr(m)); end; // ---------------- RF --------------------------------------------------------- // RF function RFC(x, y, z: variant): variant; label Ext; const r = 1E-24; c1 = 1 / 10; c2 = 1 / 14; c3 = 1 / 24; c4 = 3 / 44; var one : variant; lamda : variant; xm, ym, zm : variant; A0, Am, Q : variant; sqrtx, sqrty, sqrtz : variant; m : integer; X0, Y0, Z0 : variant; E2, E3 : variant; pt : double; begin m := 0; if Varcomplexabs(x) = 0 then inc(m); if Varcomplexabs(y) = 0 then inc(m); if Varcomplexabs(z) = 0 then inc(m); if m > 1 then begin // m := 0; result := Vc(0, 0); ZeroF := ZeroF or 2; goto Ext; end; one := Vc(1, 0); xm := x; ym := y; zm := z; A0 := (xm + ym + zm) / 3; Am := A0; Q := power(3 * r, -1 / 6) * max(Varcomplexabs(A0 - xm), max(Varcomplexabs(A0 - ym), Varcomplexabs(A0 - zm))); m := 0; repeat sqrtx := Varcomplexsqrt(xm); sqrty := Varcomplexsqrt(ym); sqrtz := Varcomplexsqrt(zm); lamda := sqrtx * (sqrty + sqrtz) + sqrty * sqrtz; xm := (xm + lamda) / 4; ym := (ym + lamda) / 4; zm := (zm + lamda) / 4; Am := (Am + lamda) / 4; m := m + 1; until power(4, -m) * Q < Varcomplexabs(Am); pt := Am.real * Am.real + Am.Imaginary * Am.Imaginary; if pt < 1E-5 then begin // 演算エラー回避 if Am.real > 0 then Am := Vc(1E-5, 0) else Am := Vc(-1E-5, 0); ERRF := ERRF or 2; end; X0 := (A0 - x) / Varcomplexpower(4, m) / Am; Y0 := (A0 - y) / Varcomplexpower(4, m) / Am; Z0 := -X0 - Y0; E2 := X0 * Y0 - Z0 * Z0; E3 := X0 * Y0 * Z0; result := VarcomplexPower(Am, -1 / 2) * (one - c1 * E2 + c2 * E3 + c3 * E2 * E2 - c4 * E2 * E3); Ext: // Form1.Memo1.Lines.Append('RF Loop数 = ' + intTostr(m)); end; // ---------------- RJ --------------------------------------------------------- function minc3(a, b, c: variant): variant; var tmp : variant; begin if Varcomplexabs(a) < Varcomplexabs(b) then tmp := a else tmp := b; if Varcomplexabs(tmp) < Varcomplexabs(c) then result := tmp else result := c; end; function maxc3(a, b, c: variant): variant; var tmp : variant; begin if Varcomplexabs(a) > Varcomplexabs(b) then tmp := a else tmp := b; if Varcomplexabs(tmp) > Varcomplexabs(c) then result := tmp else result := c; end; // RJ function RJC(x, y, z, p: variant): variant; label Ext; const r = 1E-24; c1 = 3 / 14; c2 = 1 / 6; c3 = 9 / 88; c4 = 3 / 22; c5 = 9 / 52; c6 = 3 / 26; var one : variant; rj, xt, yt, zt, pt : variant; sum, a, b, rho, A0 : variant; tau, rcx, lamda, Q : variant; m, Am : variant; sqrtx, sqrty, sqrtz, sqrtp: variant; delta, dm, em : variant; test : integer; X0, Y0, Z0, P0 : variant; E2, E3, E4, E5 : variant; pm : double; begin m := 0; if Varcomplexabs(x) = 0 then inc(m); if Varcomplexabs(y) = 0 then inc(m); if Varcomplexabs(z) = 0 then inc(m); if Varcomplexabs(p) = 0 then inc(m); if m > 1 then begin // m := 0; result := Vc(0, 0); ZeroF := ZeroF or 4; goto Ext; end; sum := Vc(0, 0); one := Vc(1, 0); if (p.real <= 0) and (y.real > 0) then test := -1 else test := 1; if test > 0 then begin xt := x; yt := y; zt := z; pt := p; a := Vc(0, 0); b := Vc(0, 0); rcx := Vc(0, 0); end else begin xt := minc3(x, y, z); zt := maxc3(x, y, z); yt := x + y + z - xt - zt; if Varcomplexabs(yt - p) > 1E-5 then a := VarComplexInverse(yt - p) // 演算エラー回避 else begin a := 1E100; ERRF := ERRF or 4; end; b := a * (zt - yt) * (yt - xt); pt := yt + b; Pm := yt.real * yt.real + yt.Imaginary * yt.Imaginary; if Pm < 1E-5 then begin // 演算エラー回避 if yt.real > 0 then yt := Vc(1E-5, 0) else yt := Vc(-1E-5, 0); ERRF := ERRF or 4; end; rho := xt * zt / yt; tau := p * pt / yt; rcx := rcc(rho, tau); end; A0 := (xt + yt + zt + pt + pt) / 5; AM := A0; delta := (pt - xt) * (pt - yt) * (pt - zt); Q := power(r / 4, -1 / 6) * max(Varcomplexabs(A0 - xt), max(Varcomplexabs(A0 - yt), max(Varcomplexabs(A0 - zt), Varcomplexabs(A0 - pt)))); m := 0; repeat sqrtx := Varcomplexsqrt(xt); sqrty := Varcomplexsqrt(yt); sqrtz := Varcomplexsqrt(zt); sqrtp := Varcomplexsqrt(pt); lamda := sqrtx * (sqrty + sqrtz) + sqrty * sqrtz; dm := (sqrtp + sqrtx) * (sqrtp + sqrty) * (sqrtp + sqrtz); Pm := dm.real * dm.real + dm.Imaginary * dm.Imaginary; if Pm < 1e-5 then begin if dm.real > 0 then dm := Vc(1E-5, 0) else dm := Vc(-1E-5, 0); ERRF := ERRF or 4; end; em := Varcomplexpower(4, -3 * m) * delta / dm / dm; sum := sum + Varcomplexpower(4, -m) / dm * Rcc(one, one + em); Am := (Am + lamda) / 4; xt := (xt + lamda) / 4; yt := (yt + lamda) / 4; zt := (zt + lamda) / 4; pt := (pt + lamda) / 4; m := m + 1; until power(4, - m) * Q < Varcomplexabs(am); X0 := (A0 - x) / Varcomplexpower(4, m) / Am; Y0 := (A0 - y) / Varcomplexpower(4, m) / Am; Z0 := (A0 - z) / Varcomplexpower(4, m) / Am; P0 := (-X0 - Y0 - Z0) / 2; E2 := X0 * Y0 + X0 * Z0 + Y0 * Z0 - 3 * P0 * P0; E3 := X0 * Y0 * Z0 + 2 * E2 * P0 + 4 * P0 * P0 * P0; Pm := P0.real * P0.real + P0.Imaginary * P0.Imaginary; if Pm > 1e-11 then // !E-11より小さいと0とみなされるので回避 E4 := (2 * X0 * Y0 * Z0 + E2 * P0 + 3 * P0 * P0 * P0) / P0 else begin E4 := Vc(0, 0); // 十分に小さいので計算結果は変わりません // ERRF := ERRF or 4; // 演算結果に影響なし end; E5 := X0 * Y0 * Z0 * P0 * P0; rj := Varcomplexpower(4, -m) * Varcomplexpower(Am, -3 / 2) * (one - c1 * E2 + c2 * E3 + c3 * E2 * E2 - c4 * E4 - c5 * E2 * E3 + c6 * E5) + 6 * sum; if test < 0 then rj := a * (b * rj + 3 * (rcx - rfc(xt, yt, zt))); result := rj; // form1.Canvas.TextOut(250,5,' '); // form1.Canvas.TextOut(250,5,'rj 判定 ' + floatTostr(test)); Ext: // Form1.Memo1.Lines.Append('RJ Loop数 = ' + intTostr(m)); end; // ---------------- Elliptic intehral Calc ------------------------------------- // 楕円積分計算 procedure TForm1.calc_Third_elliptic_integral_complex; var a, k, kmax, x, m : double; xb : double; c : variant; mc, qc : variant; rf0, rj0 : variant; afk : variant; ek, fk : variant; ac : variant; FI : boolean; qmax : double; function rinteg2: variant; // 第二種積分 begin rf0 := RFC(c - 1, c - mc, c); rj0 := RJC(c - 1, c - mc, c, c); result := rf0 - mc / 3 * rj0; end; function rinteg3(a: variant): variant; // 第一三種積分 begin rf0 := RFC(c - 1, c - mc, c); rj0 := RJC(c - 1, c - mc, c, c - a); result := rf0 + a / 3 * rj0; end; begin if not datainput(a, x, k, FI) then exit; ZeroF := 0; ERRF := 0; xb := x; x := abs(x); qc := varcomplexarcsin(x); qmax := pi / 2; m := k * k; if FI then m := -m; // kが虚数だったらm -> -m if m > 1 then begin // パラメータm ,k が1より大きかったら qmax := arcsin(1 / abs(k)); // 実数積分角度位置 end; if x = 0 then begin Edit1.Text := '0'; Edit3.Text := '0'; Edit5.Text := '0'; Edit2.Text := ''; Edit4.Text := ''; Edit6.Text := ''; exit; end; kmax := 1 / sin(qmax); // 実数積分角度位置での最大離心率計算 Memo1.Clear; Memo1.Lines.Append('実数積分角度 = ' + floatTostr(qmax / pi * 180) + '°'); Memo1.Lines.Append('最大離心率 = ±' + floatTostr(kmax)); if x <= 1 then begin Kmax := 1 / x; Memo1.Lines.Append('指定角度の最大離心率 = ±' + floatTostr(kmax)); end; c := 1 / varcomplexsin(qc) / varcomplexsin(qc); mc := Vc(m, 0); ac := Vc(a, 0); if ((a = 1) and (x = 1)) or ((m = 1) and (x = 1)) then begin afk := Vc(infinity, 0); end else begin afk := rinteg3(ac); // 第三種積分 end; if xb < 0 then afk := -afk; Edit1.Text := floatTostr(afk.real); if (m = 1) and (x = 1) then begin ek := Vc(1, 0); // 第二種 1 end else begin ek := rinteg2; // 第二種積分 end; if xb < 0 then ek := -ek; Edit3.Text := floatTostr(ek.real); if (m = 1) and (x = 1) then begin fk := Vc(infinity, 0); // 第一種∞ end else begin ac := Vc(0, 0); fk := rinteg3(ac); // 第一種積分 end; if xb < 0 then fk := -fk; Edit5.Text := floatTostr(fk.real); Edit2.Text := floatTostr(afk.Imaginary) + 'i'; Edit4.Text := floatTostr(ek.Imaginary) + 'i'; Edit6.Text := floatTostr(fk.Imaginary) + 'i'; if ERRF and 1 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RCで ゼロでの除算がありました。'); if ERRF and 2 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RFで ゼロでの除算がありました。'); if ERRF and 4 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RJで ゼロでの除算がありました。'); if ZeroF and 1 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RCで 引数 y=0 がありました。'); if ZeroF and 2 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RFで 引数 ゼロが二個 がありました。'); if ZeroF and 4 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RJで 引数 ゼロが二個 がありました。'); end; // ---------------- 入力処理 --------------------------------------------------- var XF: boolean; // データの入力 // a 第三種楕円積分特性値 n // deg 積分角度 // k 離心率 // FI 離心率 虚数フラグ true で虚数 function TForm1.datainput(var a, x, k: double; var FI: boolean): boolean; var ch, l : integer; degr, degi : double; m : double; degc, xc : Variant; kstr, kss : string; c : char; begin result := False; FI := False; val(LabeledEdit1.Text, a, ch); if ch <> 0 then begin application.MessageBox('a(特性)の値に間違いがあります。','a(特性)',0); exit; end; val(LabeledEdit2.Text, degr, ch); if ch <> 0 then begin application.MessageBox('φ(deg)の値に間違いがあります。','φ(deg)',0); exit; end; if abs(degr) > 90 then begin application.MessageBox('φ(deg)の絶対値値は90°迄です。','φ(deg)',0); exit; end; val(LabeledEdit5.Text, degi, ch); if ch <> 0 then begin application.MessageBox('φ(deg)iの値に間違いがあります。','φ(deg)',0); exit; end; if (abs(degr) < 90) and (degi <> 0) then begin application.MessageBox('φ(deg)が90°以下の場合φ(deg)iの値はゼロです。','φ(deg)',0); exit; end; if (degr * degi > 0) and (abs(degr) >= 90) then begin application.MessageBox('φ(deg)とφ(deg)iの符号は±を逆にして下さい','φ(deg)',0); exit; end; if radiobutton1.Checked = true then begin kstr := LabeledEdit3.Text; l := length(kstr); // 文字の長さ取得 c := kstr[l]; // iの文字確認 if (c = 'i') or (c = 'I') then begin // i虚数指定だったら kss := copy(kstr, 1, l - 1); // iの前までコピー FI := true; // 虚数フラグセット end else Kss := kstr; val(kss, k, ch); if ch <> 0 then begin application.MessageBox('k(離心率)の値に間違いがあります。','k(離心率)',0); exit; end; end; if radiobutton2.Checked = true then begin val(LabeledEdit6.Text, m, ch); if ch <> 0 then begin application.MessageBox('mの値に間違いがあります。','m=k^2',0); exit; end; if m < 0 then FI := true; // 虚数フラグセット k := sqrt(abs(m)); // k =√m end; degc := varascomplex(degc); xc := varascomplex(xc); // q := deg * pi / 180; degc.real := degr / 180 * pi; degc.Imaginary := degi / 180 * pi ; if not XF then begin xc := varcomplexsin(degc); LabeledEdit4.Text := floattostr(xc.real); x := xc.real; end else x := strtofloat(LabeledEdit4.Text); result := true; end; // 角度入力 procedure TForm1.Button1Click(Sender: TObject); begin XF := False; calc_Third_elliptic_integral_complex; end; // Xの値入力 procedure TForm1.Button2Click(Sender: TObject); var x : double; ch : integer; q : variant; begin q := varascomplex(q); val(LabeledEdit4.Text, x, ch); if ch <> 0 then begin application.MessageBox('Xの値に間違いがあります。','X(1≧X≧-1)',0); exit; end; XF := True; q := varcomplexarcsin(x); LabeledEdit2.Text := floatTostr(q.real / pi * 180); LabeledEdit5.Text := floatTostr(q.Imaginary / pi * 180); calc_Third_elliptic_integral_complex; end; end.
DoubleとVariantの組み合わせプログラム
RC,RF,RJの計算に、doubleの複素数を出来る限り使用した場合。
(データーの入出力は、Variantのまゝです。)
a=1 k=1 でも、89.9999°迄は、ゼロでの除算が発生しません。
角度のを入力にVariantの複素数を使用しているので、入出力も全て、Double使用すれば、もう少し、ゼロでの除算の改善が出来るかもしれませんが、全て多倍長複素数のプログラムを作成したので、このプログラムの改善はここ迄としました。
Doubleの複素数の平方根に関しては、VariantのVarcomplexに用意されている、平方根の方が、精度が高いことが判明しました。
Doubleではなく、Extendedを使用するとほゞ同じ精度の複素数の平方根を得ることができます。
// 1/31/2021 // プログラムは https://arxiv.org/abs/math/9409227 のレポートを元に作成しています。 // sin sqrt power はdelphiのVarComplexを使用します。 // 離心率k=1 角度φ=89.99995°近辺で桁落ちによる演算エラーが発生します。 // 係数a= 1 角度φ=89.99995°近辺でゼロでの除算と桁落ちが発生します。 unit Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons; type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; LabeledEdit1: TLabeledEdit; LabeledEdit2: TLabeledEdit; LabeledEdit3: TLabeledEdit; Button1: TButton; Button2: TButton; LabeledEdit4: TLabeledEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; Edit6: TEdit; Label2: TLabel; Label3: TLabel; Memo1: TMemo; LabeledEdit5: TLabeledEdit; RadioButton1: TRadioButton; RadioButton2: TRadioButton; LabeledEdit6: TLabeledEdit; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private 宣言 } function datainput(var a, x, k: double; var FI: boolean): boolean; procedure calc_Third_elliptic_integral_complex; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses system.Math, System.VarCmplx; var ZeroF : integer; ERRF : integer; // 複素数の生成 function Varcomplex(a, b: double): Variant; begin result := varascomplex(result); result.real := a; result.Imaginary := b; end; // 複素数構造体 type TCdouble = record r : double; i : double; end; // 複素数の生成 function Vc(a, b: double): Variant; begin result := varascomplex(result); result.real := a; result.Imaginary := b; end; // 複素数変換 Varint to TCdouble function VtoT(x : variant): TCdouble; begin result.r := x.real; result.i := x.Imaginary; end; // 複素数変換 TCdouble to variant; function TtoV(x : TCdouble): variant; begin result := varascomplex(result); result.real := x.r; result.Imaginary := x.i; end; // TCdouble複素数の生成 function MCdouble(r, i: double): TCdouble; begin result.r := r; result.i := i; end; // TCdouble複素数の加算 function cadd(a, b: TCdouble): TCdouble; begin result.r := a.r + b.r; result.i := a.i + b.i; end; // TCdouble複素数の減算 function csub(a, b: TCdouble): TCdouble; begin result.r := a.r - b.r; result.i := a.i - b.i; end; // TCdouble複素数の乗算 function cmul(a, b: TCdouble): TCdouble; begin result.r := a.r * b.r - a.i * b.i; result.i := a.r * b.i + a.i * b.r; end; // TCdouble複素数とDoubleの乗算 function cmuld(a: TCdouble; b: double): TCdouble; begin result.r := a.r * b; result.i := a.r * b; end; // TCdouble複素数とDoubleの除算 function cdivd(a: TCdouble; b: double): TCdouble; begin result.r := a.r / b; result.i := a.i / b; end; // TCdouble複素数の除算 function cdiv(a, b: TCdouble): TCdouble; var bb: double; begin result.r := 0; result.i := 0; bb := b.r * b.r + b.i * b.i; if bb <> 0 then begin result.r := (a.r * b.r + a.i * b.i) / bb; result.i := (a.i * b.r - a.r * b.i) / bb; end; end; // TCdouble複素数の符号反転 function cchs(a: TCdouble): TCdouble; begin result.r := -a.r; result.i := -a.i; end; // 複素数の平方根 function tsqrt(x: TCdouble): TCdouble; var xv, xs : variant; begin xv := varcomplex(x.r, x.i); xs := varcomplexsqrt(xv); result := MCdouble(xs.real, xs.imaginary); end; // 複素数 x^y 演算variant complex function tpower(x: TCdouble; p : double): TCdouble; var xv, xs : variant; begin xv := varcomplex(x.r, x.i); xs := varcomplexpower(xv, p); result := MCdouble(xs.real, xs.Imaginary); end; // 複素数の絶対値 function cabs(x: TCdouble): double; var a : double; begin a := x.r * x.r + x.i * x.i; result := sqrt(a); end; // ---------------- RC --------------------------------------------------------- // RC function RCd(x, y: TCdouble): TCdouble; label Ext; const r = 1E-24; c1d = 3 / 10; c2d = 1 / 7; c3d = 3 / 8; c4d = 9 / 22; c5d = 159 / 208; c6d = 9 / 8; var xt, yt : TCdouble; lamda, Am : TCdouble; A0, s, yb : TCdouble; one, p4, w : TCdouble; c1, c2, c3, c4, c5, c6 : TCdouble; d2 : TCdouble; tmp : TCdouble; Q : Double; m : integer; begin if cabs(y) = 0 then begin // yがゼロだったら終了 result := MCdouble(0, 0); // m := 0; ZeroF := ZeroF or 1; goto Ext; end; one := MCdouble(1, 0); c1 := MCdouble(c1d, 0); c2 := MCdouble(c2d, 0); c3 := MCdouble(c3d, 0); c4 := MCdouble(c4d, 0); c5 := MCdouble(c5d, 0); c6 := MCdouble(c6d, 0); d2 := MCdouble(2, 0); if (y.r > 0) or (y.i <> 0) then begin xt := x; yt := y; w := MCdouble(1, 0); end else begin xt := csub(x, y); yt := cchs(y); w := tsqrt(cdiv(x, xt)); end; yb := yt; A0 := cdivd(cadd(xt,cadd(yt, yt)), 3); Am := A0; Q := 1 / power(3 * r, 1 / 8) * cabs(csub(A0, xt)); m := 0; repeat lamda := cadd(cmul(d2, cmul(tsqrt(xt), tsqrt(yt))), yt); xt := cdivd(cadd(xt, lamda), 4); yt := cdivd(cadd(yt, lamda), 4); Am := cdivd(cadd(Am, lamda), 4); inc(m); until power(4, -m) * Q < cabs(Am); p4 := MCdouble(power(4, m), 0); s := cdiv(cdiv(csub(yb, A0), p4), Am); tmp := cadd(c5, cmul(s, c6)); tmp := cadd(c4, cmul(s, tmp)); tmp := cadd(c3, cmul(s, tmp)); tmp := cadd(c2, cmul(s, tmp)); tmp := cadd(c1, cmul(s, tmp)); tmp := cadd(one, cmul(s, cmul(s, tmp))); result := cdiv(cmul(w, tmp), tsqrt(Am)); // varcomplexsqrtを使用します Ext: // Form1.Memo1.Lines.Append('RC Loop数 = ' + intTostr(m)); end; // ---------------- RF --------------------------------------------------------- // RF function RFd(x, y, z: TCdouble): TCdouble; label Ext; const r = 1E-30; c1d = 1 / 10; c2d = 1 / 14; c3d = 1 / 24; c4d = 3 / 44; var one : TCdouble; lamda : TCdouble; xm, ym, zm : TCdouble; A0, Am : TCdouble; sqrtx, sqrty, sqrtz : TCdouble; m : integer; X0, Y0, Z0 : TCdouble; E2, E3 : TCdouble; c1, c2, c3, c4 : TCdouble; d3, d4, p4, tmp : TCdouble; Q : double; begin m := 0; if cabs(x) = 0 then inc(m); if cabs(y) = 0 then inc(m); if cabs(z) = 0 then inc(m); if m > 1 then begin // ゼロが二個有ったら終了 // m := 0; result := MCdouble(0, 0); ZeroF := ZeroF or 2; goto Ext; end; one := MCdouble(1, 0); c1 := MCdouble(c1d, 0); c2 := MCdouble(c2d, 0); c3 := MCdouble(c3d, 0); c4 := MCdouble(c4d, 0); d3 := MCdouble(3, 0); d4 := MCdouble(4, 0); xm := x; ym := y; zm := z; A0 := cdiv(cadd(xm, cadd(ym, zm)), d3); Am := A0; Q := power(3 * r, -1 / 6) * max(cabs(csub(A0, xm)), max(cabs(csub(A0, ym)), cabs(csub(A0, zm)))); m := 0; repeat sqrtx := tsqrt(xm); sqrty := tsqrt(ym); sqrtz := tsqrt(zm); lamda := cadd(cmul(sqrtx,(cadd(sqrty, sqrtz))), cmul(sqrty,sqrtz)); xm := cdivd(cadd(xm, lamda), 4); ym := cdivd(cadd(ym, lamda), 4); zm := cdivd(cadd(zm, lamda), 4); Am := cdivd(cadd(Am, lamda), 4); m := m + 1; until power(4, -m) * Q < cabs(Am); p4 := MCdouble(power(4, m), 0); X0 := cdiv(cdiv(csub(A0, x), p4), Am); Y0 := cdiv(cdiv(csub(A0, y), p4), Am); Z0 := csub(cchs(X0), Y0); E2 := csub(cmul(X0, Y0), cmul(Z0, Z0)); E3 := cmul(X0, cmul(Y0, Z0)); tmp := csub(one, cmul(c1, E2)); tmp := cadd(tmp, cmul(c2, E3)); tmp := cadd(tmp, cmul(E2, cmul(c3, E2))); tmp := csub(tmp, cmul(E3,cmul(c4, E2))); result := cmul(cdiv(one, tsqrt(Am)), tmp); // varcomplexsqrtを使用します Ext: // Form1.Memo1.Lines.Append('RF Loop数 = ' + intTostr(m)); end; // ---------------- RJ --------------------------------------------------------- // 複素数3個の最小値 function minc3d(a, b, c: TCdouble): TCdouble; var tmp : TCdouble; begin if cabs(a) < cabs(b) then tmp := a else tmp := b; if cabs(tmp) < cabs(c) then result := tmp else result := c; end; // 複素数3個の最大値 function maxc3d(a, b, c: TCdouble): TCdouble; var tmp : TCdouble; begin if cabs(a) > cabs(b) then tmp := a else tmp := b; if cabs(tmp) > cabs(c) then result := tmp else result := c; end; // RJ function RJd(x, y, z, p: TCdouble): TCdouble; label Ext; const r = 1E-30; var one : TCdouble; rj, xt, yt, zt, pt : TCdouble; sum, a, b, rho, A0 : TCdouble; tau, rcx, lamda, Am : TCdouble; sqrtx, sqrty, sqrtz, sqrtp, dm, em : TCdouble; delta : TCdouble; c1, c2, c3 : TCdouble; c4, c5, c6 : TCdouble; X0, Y0, Z0, P0 : TCdouble; E2, E3, E4, E5 : TCdouble; d0, d2, d3, d4, d5, d6 : TCdouble; p4 : TCdouble; powa, def : TCdouble; Q, pm : double; test, m : integer; begin m := 0; if cabs(x) = 0 then inc(m); if cabs(y) = 0 then inc(m); if cabs(z) = 0 then inc(m); if cabs(p) = 0 then inc(m); if m > 1 then begin // ゼロが二個有ったら終了 // m := 0; result := MCdouble(0, 0); ZeroF := ZeroF or 4; goto Ext; end; c1 := MCdouble(3 / 14, 0); c2 := MCdouble(1 / 6, 0); c3 := MCdouble(9 / 88, 0); c4 := MCdouble(3 / 22, 0); c5 := MCdouble(9 / 52, 0); c6 := MCdouble(3 / 26, 0); d0 := MCdouble(0, 0); d2 := MCdouble(2, 0); d3 := MCdouble(3, 0); d4 := MCdouble(4, 0); d5 := MCdouble(5, 0); d6 := MCdouble(6, 0); sum := MCdouble(0, 0); one := MCdouble(1, 0); if (p.r <= 0) and (y.r > 0) then test := -1 else test := 1; if test > 0 then begin xt := x; yt := y; zt := z; pt := p; a := MCdouble(0, 0); b := MCdouble(0, 0); rcx := MCdouble(0, 0); end else begin xt := minc3d(x, y, z); zt := maxc3d(x, y, z); yt := cadd(x, cadd(y, csub(z, cadd(xt, zt)))); if cabs(csub(yt, p)) <> 0 then a := cdiv(one, csub(yt, p)) // 演算エラー回避 else begin a := MCdouble(+1E100, 0); ERRF := ERRF or 4; end; b := cmul(cmul(a, csub(zt, yt)), csub(yt, xt)); pt := cadd(yt, b); rho := cmul(xt, cdiv(zt, yt)); tau := cmul(p, cdiv(pt, yt)); rcx := rcd(rho, tau); end; A0 := cdiv(cadd(xt, cadd(yt, cadd(zt, cadd(pt, pt)))), d5); AM := A0; delta := cmul(csub(pt, xt), cmul(csub(pt, yt), csub(pt, zt))); Q := power(r / 4, -1 / 6) * max(cabs(csub(A0, xt)), max(cabs(csub(A0, yt)), max(cabs(csub(A0, zt)), cabs(csub(A0, pt))))); m := 0; repeat sqrtx := tsqrt(xt); sqrty := tsqrt(yt); sqrtz := tsqrt(zt); sqrtp := tsqrt(pt); lamda := cadd(cmul(sqrtx, cadd(sqrty, sqrtz)), cmul(sqrty, sqrtz)); dm := cmul(cadd(sqrtp, sqrtx), cmul(cadd(sqrtp, sqrty), cadd(sqrtp,sqrtz))); p4 := tpower(d4, -3 * m); em := cdiv(cdiv(cmul(p4, delta), dm), dm); p4 := tpower(d4, -m); def := Rcd(one, cadd(one, em)); sum := cadd(sum, cmul(cdiv(p4, dm), def)); Am := cdivd(cadd(Am, lamda), 4); xt := cdivd(cadd(xt, lamda), 4); yt := cdivd(cadd(yt, lamda), 4); zt := cdivd(cadd(zt, lamda), 4); pt := cdivd(cadd(pt, lamda), 4); m := m + 1; until power(4, -m) * Q < cabs(am); p4 := tpower(d4, m); X0 := cdiv(cdiv(csub(A0, x), p4), Am); Y0 := cdiv(cdiv(csub(A0, y), p4), Am); Z0 := cdiv(cdiv(csub(A0, z), p4), Am); P0 := cdivd(csub(csub(csub(d0, X0), Y0), Z0), 2); E2 := csub(cmul(Y0, Z0), cmul(d3, cmul(P0, P0))); E2 := cadd(cmul(X0, Y0), cadd(cmul(X0, Z0), E2)); E3 := cmul(d4, cmul(P0, cmul(P0, P0))); E3 := cadd(cmul(X0, cmul(Y0, Z0)), cadd(cmul(d2, cmul(E2, P0)), E3)); Pm := P0.r * P0.r + P0.i * P0.i; if Pm > 1e-100 then begin // 分母ゼロ回避 E4 := cadd(cmul(E2, P0), cmul(d3, cmul(P0, cmul(P0, P0)))); E4 := cadd(cmul(d2, cmul(X0, cmul(Y0, Z0))), E4); E4 := cdiv(E4, P0); end else E4 := MCdouble(0, 0); E5 := cmul(X0, cmul(Y0, cmul(Z0, cmul(P0, P0)))); p4 := tpower(d4, -m); powa := tpower(Am, -3 / 2); def := csub(one, cmul(c1, E2)); def := cadd(def, cmul(c2, E3)); def := cadd(def, cmul(c3, cmul(E2, E2))); def := csub(def, cmul(c4, E4)); def := csub(def, cmul(c5, cmul(E2, E3))); def := cadd(def, cmul(c6, E5)); rj := cadd(cmul(p4, cmul(powa, def)), cmul(d6, sum)); if test < 0 then rj := cmul(a, (cadd(cmul(b ,rj), cmul(d3, csub(rcx, rfd(xt, yt, zt)))))); result := rj; // form1.Canvas.TextOut(250,320,' '); // form1.Canvas.TextOut(250,320,'rj 判定 ' + floatTostr(test)); Ext: // Form1.Memo1.Lines.Append('RJ Loop数 = ' + intTostr(m)); end; // ---------------- Elliptic intehral Calc ------------------------------------- // 楕円積分計算 procedure TForm1.calc_Third_elliptic_integral_complex; var a, k, kmax, x, m : double; c, xc : variant; mc : variant; rf0, rj0 : variant; rft, rjt : TCdouble; afk : variant; ek, fk : variant; ac : variant; tc1, tcm, tc : TCdouble; tca : TCdouble; FI : boolean; qmax, xb : double; function rinteg2: variant; // 第二種積分 begin tc1 := VtoT(c - 1); tcm := VtoT(c - mc); tc := VtoT(c); rft := RFd(tc1, tcm, tc); rjt := RJd(tc1, tcm, tc, tc); rf0 := TtoV(rft); rj0 := TtoV(rjt); result := rf0 - mc / 3 * rj0; end; function rinteg3(a: variant): variant; // 第一三種積分 begin tc1 := VtoT(c - 1); tcm := VtoT(c - mc); tc := VtoT(c); tca := VtoT(c - a); rft := RFd(tc1, tcm, tc); rjt := RJd(tc1, tcm, tc, tca); rf0 := TtoV(rft); rj0 := TtoV(rjt); result := rf0 + a / 3 * rj0; end; begin if not datainput(a, x, k, FI) then exit; ERRF := 0; ZeroF := 0; xc := varascomplex(xc); xb := x; x := abs(x); xc.real := x; xc.Imaginary := 0; qmax := pi / 2; m := k * k; if FI then m := -m; // kが虚数だったらm -> -m if m > 1 then begin // パラメータm ,k が1より大きかったら qmax := arcsin(1 / abs(k)); // 実数積分角度位置 end; if x = 0 then begin Edit1.Text := '0'; Edit3.Text := '0'; Edit5.Text := '0'; Edit2.Text := ''; Edit4.Text := ''; Edit6.Text := ''; exit; end; kmax := 1 / sin(qmax); // 実数積分角度位置での最大離心率計算 Memo1.Clear; Memo1.Lines.Append('実数積分角度 = ' + floatTostr(qmax / pi * 180) + '°'); Memo1.Lines.Append('最大離心率 = ±' + floatTostr(kmax)); if x <= 1 then begin kmax := 1 / x; // 実数積分角度位置での最大離心率計算 Memo1.Lines.Append('指定角度の最大離心率 = ±' + floatTostr(kmax)); end; c := 1 / xc / xc; mc := Vc(m, 0); ac := Vc(a, 0); if ((a = 1) and (x = 1)) or ((m = 1) and (x = 1)) then begin afk := Vc(infinity, 0); end else begin afk := rinteg3(ac); // 第三種積分 end; if xb < 0 then afk := -afk; Edit1.Text := floatTostr(afk.real); if (m = 1) and (x = 1) then begin ek := Vc(1, 0); // 第二種 1 end else begin ek := rinteg2; // 第二種積分 end; if xb < 0 then ek := -ek; Edit3.Text := floatTostr(ek.real); if (m = 1) and (x = 1) then begin fk := Vc(infinity, 0); // 第一種∞ end else begin ac := Vc(0, 0); fk := rinteg3(ac); // 第一種積分 end; if xb < 0 then fk := -fk; Edit5.Text := floatTostr(fk.real); Edit2.Text := floatTostr(afk.Imaginary) + 'i'; Edit4.Text := floatTostr(ek.Imaginary) + 'i'; Edit6.Text := floatTostr(fk.Imaginary) + 'i'; if ERRF and 4 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + ('RJ ゼロでの除算がありました。'); if ZeroF and 1 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RCで 引数 y=0 がありました。'); if ZeroF and 2 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RFで 引数 ゼロが二個 がありました。'); if ZeroF and 4 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RJで 引数 ゼロが二個 がありました。'); end; // ---------------- 入力処理 --------------------------------------------------- var XF: boolean; // データの入力 // a 第三種楕円積分特性値 n // deg 積分角度 // k 離心率 // FI 離心率 虚数フラグ true で虚数 function TForm1.datainput(var a, x, k: double; var FI: boolean): boolean; var ch, l : integer; degr, degi : double; m : double; degc, xc : Variant; kstr, kss : string; c : char; begin result := False; FI := False; val(LabeledEdit1.Text, a, ch); if ch <> 0 then begin application.MessageBox('a(特性)の値に間違いがあります。','a(特性)',0); exit; end; val(LabeledEdit2.Text, degr, ch); if ch <> 0 then begin application.MessageBox('φ(deg)の値に間違いがあります。','φ(deg)',0); exit; end; if abs(degr) > 90 then begin application.MessageBox('φ(deg)の絶対値値は90°迄です。','φ(deg)',0); exit; end; val(LabeledEdit5.Text, degi, ch); if ch <> 0 then begin application.MessageBox('φ(deg)iの値に間違いがあります。','φ(deg)',0); exit; end; if (abs(degr) < 90) and (degi <> 0) then begin application.MessageBox('φ(deg)が90°以下の場合φ(deg)iの値はゼロです。','φ(deg)',0); exit; end; if (degr * degi > 0) and (abs(degr) >= 90) then begin application.MessageBox('φ(deg)とφ(deg)iの符号は±を逆にして下さい','φ(deg)',0); exit; end; if radiobutton1.Checked = true then begin kstr := LabeledEdit3.Text; l := length(kstr); // 文字の長さ取得 c := kstr[l]; // iの文字確認 if (c = 'i') or (c = 'I') then begin // i虚数指定だったら kss := copy(kstr, 1, l - 1); // iの前までコピー FI := true; // 虚数フラグセット end else Kss := kstr; val(kss, k, ch); end; if ch <> 0 then begin application.MessageBox('k(離心率)の値に間違いがあります。','k(離心率)',0); exit; end; if radiobutton2.Checked = true then begin val(LabeledEdit6.Text, m, ch); if ch <> 0 then begin application.MessageBox('mの値に間違いがあります。','m=k^2',0); exit; end; if m < 0 then FI := true; // 虚数フラグセット k := sqrt(abs(m)); // k =√m end; degc := varascomplex(degc); xc := varascomplex(xc); // q := deg * pi / 180; degc.real := degr / 180 * pi; degc.Imaginary := degi / 180 * pi ; if not XF then begin xc := varcomplexsin(degc); LabeledEdit4.Text := floattostr(xc.real); x := xc.real; end else x := strtofloat(LabeledEdit4.Text); result := true; end; procedure TForm1.Button1Click(Sender: TObject); begin XF := False; calc_Third_elliptic_integral_complex; end; procedure TForm1.Button2Click(Sender: TObject); var x : double; xc : variant; ch : integer; q : variant; begin val(LabeledEdit4.Text, x, ch); if ch <> 0 then begin application.MessageBox('Xの値に間違いがあります。','X(1≧X≧-1)',0); exit; end; XF := True; q := varascomplex(q); xc := varascomplex(xc); xc.real := x; xc.Imaginary := 0;; q := varcomplexarcsin(xc); LabeledEdit2.Text := floatTostr(q.real / pi * 180); LabeledEdit5.Text := floatTostr(q.Imaginary / pi * 180); calc_Third_elliptic_integral_complex; end; end.
多倍長演算による楕円積分
多倍長の組み込みは MPArithからmparith_2018-11-27.zipをダウンロードして下さい。
Zipファイルを解凍して、解凍したフォルダーにパス(ツール->オプション->Delphiオプション->ライブラリ->ライブラリパス)を追加し、Uses に mp_types, mp_real, mp_cmplx,
mp_baseを追加すれば使用可能になります。
各値の入力条件は、Variant複素数の計算と同じです。
演算の有効桁数が74桁と多いので、桁落ちによるゼロでの除算は発生しません。
(全ての条件でテストはしていませんので発生の可能性はあります。)
複素数の演算は、非常に演算時間がかかります。
値が無限大になる条件の場合、値にMaxdoubleの値を返すと同時に無限大のフラグを使用して、無限大の表示をしています。
多倍長の値にInfinityが無い為です。
演算精度として50桁程度出る様に、収束判定値を設定しています。
データーの入力は、テキストから直接多倍長に変換するルーチンを使用しています、一旦Doubleに変換してから多倍長にした方が簡単なのですが、Doubleに変換するときの桁落ちをなくす為です。
入力データーの入力ミスの確認は、Doubleで確認し、実際の多倍長への入力は、直接変換しているので、コンパイル時、Doubleの変数に入力された値が使用されていませんと、警告がでますが無視をして下さい。
多倍長プログラム
プログラムの内容は、Variant複素数と同じですが、多倍長は Function が使用出来ないので、非常に長くなっています。
// 1/31/2021 // プログラムは https://arxiv.org/abs/math/9409227 のレポートを元に作成しています // 引数のエラー 桁落ちによるゼロでの除算回避を入れてありますが桁数が多い為発生しないようです。 unit Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons, mp_real, mp_cmplx, mp_types, mp_base; type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; LabeledEdit1: TLabeledEdit; LabeledEdit2: TLabeledEdit; LabeledEdit3: TLabeledEdit; Button1: TButton; Button2: TButton; LabeledEdit4: TLabeledEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; Edit6: TEdit; Label2: TLabel; Label3: TLabel; Memo1: TMemo; LabeledEdit5: TLabeledEdit; RadioButton1: TRadioButton; RadioButton2: TRadioButton; LabeledEdit6: TLabeledEdit; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private 宣言 } function datainput(var ac, xc, kc: mp_complex): boolean; procedure calc_Third_elliptic_integral_complex; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses system.Math; var ERRF : integer; ZeroF : integer; //============================================================================== procedure mpf_max(x, y: mp_float; var ans: mp_float); begin if mpf_is_gt(x, y) then mpf_copy(x, ans) else mpf_copy(y, ans); end; // ---------------- RC --------------------------------------------------------- // RC procedure RCd(x, y: mp_complex; var ans: mp_complex); label Ext; const r = 1E-200; c1d = 3 / 10; c2d = 1 / 7; c3d = 3 / 8; c4d = 9 / 22; c5d = 159 / 208; c6d = 9 / 8; var xt, yt : mp_complex; lamda, Am : mp_complex; A0, s, yb : mp_complex; one, p4, w : mp_complex; c1, c2, c3 : mp_complex; c4, c5, c6 : mp_complex; d2 : mp_complex; sqrtx, sqrty : mp_complex; tmp, tmpa : mp_complex; Q, tmpf, tmpaf : mp_float; m : integer; begin mpc_init2(xt, yt); mpc_init2(lamda, Am); mpc_init3(A0, s, yb); mpc_init3(one, p4, w); mpc_init3(c1, c2, c3); mpc_init3(c4, c5, c6); mpc_init2(sqrtx, sqrty); mpc_init2(tmp, tmpa); mpc_init(d2); mpf_init3(Q, tmpf, tmpaf); mpc_abs(y, tmpf); if mpf_is0(tmpf) then begin // yがゼロだったら終了 mpc_set_dbl(ans, 0, 0); ZeroF := ZeroF or 1; goto Ext; end; mpc_set_dbl(one, 1, 0); mpc_set_dbl(c1, c1d, 0); mpc_set_dbl(c2, c2d, 0); mpc_set_dbl(c3, c3d, 0); mpc_set_dbl(c4, c4d, 0); mpc_set_dbl(c5, c5d, 0); mpc_set_dbl(c6, c6d, 0); mpc_set_dbl(d2, 2, 0); if s_mpf_is_gt0(y.re) or not s_mpf_is0(y.im) then begin mpc_copy(x, xt); mpc_copy(y, yt); mpc_set1(w); end else begin mpc_sub(x, y, xt); mpc_chs(y, yt); mpc_div(x, xt, w); mpc_sqrt(w, w); end; mpc_copy(yt, yb); // yb = yt mpc_add(yt, yt, tmp); // yt + yt mpc_add(tmp, xt, tmp); // 2yt + xt mpc_div_dbl(tmp, 3, A0); // (2yt + xt) / 3 mpc_copy(A0, Am); // Am = A0 mpf_set_dbl(tmpf, 3 * r); // 3 * r mpf_set_dbl(tmpaf, 1 / 8); // 1 / 8 mpf_expt(tmpf, tmpaf, tmpf); // power(3 * r, 1 / 8) mpf_inv(tmpf, tmpf); // 1 / power(3 * r, 1 / 8) mpc_sub(A0, xt, tmpa); // A0 - xt mpc_abs(tmpa, tmpaf); // abs(A0 - xt) mpf_mul(tmpf, tmpaf, Q); // Q = 1 / power(3 * r, 1 / 8) * abs(A0 - xt) m := 0; repeat mpc_sqrt(xt, sqrtx); // √x mpc_sqrt(yt, sqrty); // √y mpc_mul(sqrtx, sqrty, tmp); // sqrtx * sqrty mpc_mul(d2, tmp, tmpa); // 2 * (sqrtx * sqrty) mpc_add(tmpa, yt, lamda); // lamda = 2 * (sqrtx * sqrty) + y mpc_add(xt, lamda, tmp); // x + lamda mpc_div_dbl(tmp, 4.0, xt); // x = (x + lamda) / 4 mpc_add(yt, lamda, tmp); // y + lamda mpc_div_dbl(tmp, 4.0, yt); // y = (y + lamda) / 4 mpc_add(Am, lamda, tmp); // Am + lamda mpc_div_dbl(tmp, 4.0, Am); // Am = (Am + lamda) / 4 inc(m); mpf_set_dbl(tmpf, 4); // 4 mpf_set_dbl(tmpaf, -m); // -m mpf_expt(tmpf, tmpaf, tmpf); // 4^-m mpf_mul(tmpf, Q, tmpaf); // 4^-m * Q mpc_abs(Am, tmpf); // abs(am) until mpf_is_lt(tmpaf,tmpf); // power(4, -m) * Q < cabs(Am) mpf_set_int(tmpf, 4); mpf_set_int(tmpaf, m); mpf_expt(tmpf, tmpaf, tmpf); // 4^m mpf_set_int(tmpaf, 0); mpc_set_mpf(p4, tmpf, tmpaf); // p4 = 4^m + 0i mpc_sub(yb, A0, tmp); // yb - A0 mpc_div(tmp, p4, tmpa); // (yb - A0) / p4 mpc_div(tmpa, Am, s); // s = (yb - A0) / p4 / Am mpc_mul(s, c6, tmpa); mpc_add(tmpa, c5, tmp); mpc_mul(s, tmp, tmpa); mpc_add(tmpa, c4, tmp); mpc_mul(s, tmp, tmpa); mpc_add(tmpa, c3, tmp); mpc_mul(s, tmp, tmpa); mpc_add(tmpa, c2, tmp); mpc_mul(s, tmp, tmpa); mpc_add(tmpa, c1, tmp); mpc_mul(s, tmp, tmpa); mpc_mul(s, tmpa, tmp); mpc_add(one, tmp, tmpa); mpc_mul(w, tmpa, tmp); // w * ??? mpc_sqrt(Am, tmpa); mpc_div(tmp, tmpa, ans); // ans = w * ???? / sqrt(Am) Ext: mpc_clear2(xt, yt); mpc_clear2(lamda, Am); mpc_clear3(A0, s, yb); mpc_clear3(one, p4, w); mpc_clear3(c1, c2, c3); mpc_clear3(c4, c5, c6); mpc_clear2(sqrtx, sqrty); mpc_clear2(tmp, tmpa); mpc_clear(d2); mpf_clear3(Q, tmpf, tmpaf); end; // ---------------- RF --------------------------------------------------------- // RF procedure RFd(x, y, z: mp_complex; var ans : mp_complex); label Ext; const r = 1E-200; c1d = 1 / 10; c2d = 1 / 14; c3d = 1 / 24; c4d = 3 / 44; var one : mp_complex; lamda : mp_complex; xm, ym, zm : mp_complex; A0, Am : mp_complex; sqrtx, sqrty, sqrtz : mp_complex; m : integer; X0, Y0, Z0 : mp_complex; E2, E3 : mp_complex; c1, c2, c3, c4 : mp_complex; d3, d4, p4, tmp : mp_complex; tmpa, tmpb, tmpc : mp_complex; tmpf, tmpaf, tmpbf : mp_float; Q, M4 : mp_float; begin mpc_init2(one, lamda); mpc_init3(xm, ym, zm); mpc_init2(A0, Am); mpc_init3(sqrtx, sqrty, sqrtz); mpc_init3(X0, Y0, Z0); mpc_init2(E2, E3); mpc_init4(c1, c2, c3, c4); mpc_init4(d3, d4, p4, tmp); mpc_init3(tmpa, tmpb, tmpc); mpf_init3(tmpf, tmpaf, tmpbf); mpf_init2(Q, M4); m := 0; mpc_abs(x, tmpf); if mpf_is0(tmpf) then inc(m); mpc_abs(y, tmpf); if mpf_is0(tmpf) then inc(m); mpc_abs(z, tmpf); if mpf_is0(tmpf) then inc(m); if m > 1 then begin // ゼロ二個有ったら終了 mpc_set_dbl(ans, 0, 0); ZeroF := ZeroF or 2; goto Ext; end; mpc_set1(one); mpc_set_dbl(c1, c1d, 0); mpc_set_dbl(c2, c2d, 0); mpc_set_dbl(c3, c3d, 0); mpc_set_dbl(c4, c4d, 0); mpc_set_dbl(d3, 3, 0); mpc_set_dbl(d4, 4, 0); mpf_set_dbl(M4, 4); mpc_copy(x, xm); mpc_copy(y, ym); mpc_copy(z, zm); mpc_add(ym, zm, tmp); // x + y mpc_add(tmp, xm, tmpa); // x + y + z mpc_div(tmpa, d3, A0); // (x + y + z) / 3 mpc_copy(A0, Am); // Am = A0 mpc_sub(A0, xm, tmp); // A0 - x mpc_sub(A0, ym, tmpa); // A0 - Y mpc_sub(A0, zm, tmpb); // A0 - z mpc_abs(tmp, tmpf); // |A0 - x| mpc_abs(tmpa, tmpaf); // |A0 - y| mpc_abs(tmpb, tmpbf); // |A0 - z| mpf_max(tmpf, tmpaf, tmpf); // max(|A0-x|,|A0-y|) mpf_max(tmpf, tmpbf, tmpf); // max(|A0-x|,|A0-y|,|A0-z|) mpf_set_dbl(tmpaf, 3 * r); // (3 * r) mpf_set_dbl(tmpbf, -1 / 6); // -1/6 mpf_expt(tmpaf, tmpbf, tmpaf); // (3 * r)^-1/6 or (3 / r)^1/6 mpf_mul(tmpf, tmpaf, Q); // Q = (3 * r)^-1/6 * max((A0-x),(A0-y),(A0-z)) m := 0; repeat mpc_sqrt(xm, sqrtx); // √x mpc_sqrt(ym, sqrty); // √y mpc_sqrt(zm, sqrtz); // √z mpc_mul(sqrty, sqrtz, tmp); // √y * √z mpc_add(sqrty, sqrtz, tmpa); // √y + √z mpc_mul(tmpa, sqrtx, tmpc); // (√y + √z) * √x mpc_add(tmpc, tmp, lamda); // lamda = √x√y + √x√z + √y√z mpc_add(xm, lamda, tmp); // xm + lamda mpc_div(tmp, d4, xm); // zm = (xm + lamda) / 4 mpc_add(ym, lamda, tmp); // ym + lamda mpc_div(tmp, d4, ym); // ym = (ym + lamda) / 4 mpc_add(zm, lamda, tmp); // zm + lamda mpc_div(tmp, d4, zm); // zm = (zm + lamda) / 4 mpc_add(Am, lamda, tmp); // Am + lamda mpc_div(tmp, d4, Am); // Am = (Am + lamda) / 4 m := m + 1; // inc(m) mpf_set_int(tmpaf, -m); // -m mpf_expt(M4, tmpaf, tmpbf); // 4^-m mpf_mul(tmpbf, Q, tmpf); // 4^-m * Q mpc_abs(Am, tmpaf); // abs(Am) until mpf_is_lt(tmpf, tmpaf); // 4^-m * Q < abs(Am) mpf_set_int(tmpaf, m); // m mpf_expt(M4, tmpaf, tmpf); // 4^m mpf_set0(tmpbf); // 0 mpc_set_mpf(P4, tmpf, tmpbf); // P4 = (4^m, 0i) mpc_sub(A0, x, tmp); // A0 - x mpc_div(tmp, p4, tmpa); // (A0 - x) / 4^m mpc_div(tmpa, Am, X0); // X0 = (A0 - x) / 4^m / Am mpc_sub(A0, y, tmp); // A0 - y mpc_div(tmp, p4, tmpa); // (A0 - y) / 4^m mpc_div(tmpa, Am, Y0); // Y0 = (A0 - y) / 4^m / Am mpc_chs(X0, tmp); // -X0 mpc_sub(tmp, Y0, Z0); // Z0 = -X0 - Y0 mpc_mul(Z0, Z0, tmpa); // Z0^2 mpc_mul(X0, Y0, tmpb); // X0 * Y0 mpc_sub(tmpb, tmpa, E2); // E2 = X0 * Y0 - Z0^2 mpc_mul(X0, Y0, tmpa); // X0 * Y0 mpc_mul(tmpa, Z0, E3); // E3 = X0 * Y0 * Z0 mpc_mul(c1, E2, tmpa); // c1 * E2 mpc_sub(one, tmpa, tmp); // 1 - C1 * E2 mpc_mul(c2, E3, tmpa); // c2 * E3 mpc_add(tmp, tmpa, tmp); // 1 - C1 * E2 + c2 * E3 mpc_mul(c3, E2, tmpa); // c3 * E2 mpc_mul(tmpa, E2, tmpb); // c3 * E2^2 mpc_add(tmp, tmpb, tmp); // 1 - C1 * E2 + c2 * E3 + c3 * E2^2 mpc_mul(c4, E2, tmpa); // c4 * E2 mpc_mul(tmpa, E3, tmpb); // c4 * E2 * E3 mpc_sub(tmp, tmpb, tmp); // 1 - C1 * E2 + c2 * E3 + c3 * E2^2 - c4 * E2 * E3 mpc_sqrt(Am, tmpc); // √Am mpc_div(one, tmpc, tmpb); // 1 / √Am mpc_mul(tmpb, tmp, ans); // ans = 1 / √Am * (1 - C1 * E2 + c2 * E3 + c3 * E2^2 - c4 * E2 * E3 Ext: mpc_clear2(one, lamda); mpc_clear3(xm, ym, zm); mpc_clear2(A0, Am); mpc_clear3(sqrtx, sqrty, sqrtz); mpc_clear3(X0, Y0, Z0); mpc_clear2(E2, E3); mpc_clear4(c1, c2, c3, c4); mpc_clear4(d3, d4, p4, tmp); mpc_clear3(tmpa, tmpb, tmpc); mpf_clear3(tmpf, tmpaf, tmpbf); mpf_clear2(Q, M4); end; // ---------------- RJ --------------------------------------------------------- // 複素数3個の最小値 procedure minc3d(a, b, c: mp_complex; var ans: mp_complex); var tmp : mp_complex; ma, mb, mc : mp_float; begin mpc_init(tmp); mpf_init3(ma, mb, mc); mpc_abs(a, ma); mpc_abs(b, mb); mpc_abs(c, mc); if mpf_is_lt(ma, mb) then mpc_copy(a, tmp) else mpc_copy(b, tmp); mpc_abs(tmp, ma); if mpf_is_lt(mc, ma) then mpc_copy(c, ans) else mpc_copy(tmp, ans); mpc_clear(tmp); mpf_clear3(ma, mb, mc); end; // 複素数3個の最大値 procedure maxc3d(a, b, c: mp_complex; var ans: mp_complex); var tmp : mp_complex; ma, mb, mc : mp_float; begin mpc_init(tmp); mpf_init3(ma, mb, mc); mpc_abs(a, ma); mpc_abs(b, mb); mpc_abs(c, mc); if mpf_is_lt(ma, mb) then mpc_copy(b, tmp) else mpc_copy(a, tmp); mpc_abs(tmp, ma); if mpf_is_lt(mc, ma) then mpc_copy(tmp, ans) else mpc_copy(c, ans); mpc_clear(tmp); mpf_clear3(ma, mb, mc); end; // 複素数4個の最大値 procedure maxc4d(a, b, c, d: mp_complex; var ans: mp_complex); var tmp : mp_complex; ma, mb, mc, md : mp_float; begin mpc_init(tmp); mpf_init4(ma, mb, mc, md); mpc_abs(a, ma); mpc_abs(b, mb); mpc_abs(c, mc); mpc_abs(d, md); if mpf_is_lt(mb, ma) then mpc_copy(a, tmp) else mpc_copy(b, tmp); mpc_abs(tmp, ma); if mpf_is_lt(ma, mc) then mpc_copy(c, tmp); mpc_abs(tmp, ma); if mpf_is_lt(ma, md) then mpc_copy(d, ans) else mpc_copy(tmp, ans); mpc_clear(tmp); mpf_clear4(ma, mb, mc, md); end; // RJ procedure RJd(x, y, z, p: mp_complex; var ans: mp_complex); label Ext; const r = 1E-300; var one : mp_complex; rj, xt, yt, zt, pt : mp_complex; sum, a, b, rho, A0 : mp_complex; tau, rcx, lamda, Am : mp_complex; sqrtx, sqrty, sqrtz, sqrtp : mp_complex; dm, em, delta : mp_complex; c1, c2, c3 : mp_complex; c4, c5, c6 : mp_complex; X0, Y0, Z0, P0 : mp_complex; E2, E3, E4, E5 : mp_complex; d0, d2, d3, d4, d5 : mp_complex; d6, p4, powa, def : mp_complex; tmpa, tmpb, tmpc, tmpd : mp_complex; tmpaf, tmpbf, tmpcf : mp_float; Q, pm : mp_float; test, m : integer; begin mpc_init(one); mpc_init5(rj, xt, yt, zt, pt); mpc_init5(sum, a, b, rho, A0); mpc_init4(tau, rcx, lamda, Am); mpc_init4(sqrtx, sqrty, sqrtz, sqrtp); mpc_init3(dm, em, delta); mpc_init3(c1, c2, c3); mpc_init3(c4, c5, c6); mpc_init4(X0, Y0, Z0, P0); mpc_init4(E2, E3, E4, E5); mpc_init5(d0, d2, d3, d4, d5); mpc_init4(d6, p4, powa, def); mpc_init4(tmpa, tmpb, tmpc, tmpd); mpf_init3(tmpaf, tmpbf, tmpcf); mpf_init2(Q, pm); m := 0; mpc_abs(x, tmpaf); if mpf_is0(tmpaf) then inc(m); mpc_abs(y, tmpaf); if mpf_is0(tmpaf) then inc(m); mpc_abs(z, tmpaf); if mpf_is0(tmpaf) then inc(m); mpc_abs(p, tmpaf); if mpf_is0(tmpaf) then inc(m); if m > 1 then begin // ゼロが二個有ったら終了 mpc_set_dbl(ans, 0, 0); ZeroF := ZeroF or 4; goto Ext; end; mpc_set_dbl(c1, 3 / 14, 0); mpc_set_dbl(c2, 1 / 6, 0); mpc_set_dbl(c3, 9 / 88, 0); mpc_set_dbl(c4, 3 / 22, 0); mpc_set_dbl(c5, 9 / 52, 0); mpc_set_dbl(c6, 3 / 26, 0); mpc_set_dbl(d0, 0, 0); mpc_set_dbl(d2, 2, 0); mpc_set_dbl(d3, 3, 0); mpc_set_dbl(d4, 4, 0); mpc_set_dbl(d5, 5, 0); mpc_set_dbl(d6, 6, 0); mpc_set_dbl(sum, 0, 0); mpc_set_dbl(one, 1, 0); if s_mpf_is_le0(p.re) and s_mpf_is_gt0(y.re) then test := -1 else test := 1; if test > 0 then begin mpc_copy(x, xt); mpc_copy(y, yt); mpc_copy(z, zt); mpc_copy(p, pt); mpc_set_dbl(a, 0, 0); mpc_set_dbl(b, 0, 0); mpc_set_dbl(rcx, 0, 0); end else begin minc3d(x, y, z, xt); // xt = min(x, y, z) maxc3d(x, y, z, zt); // zt = max(x, y, z) mpc_add(xt, zt, tmpa); // xt + zt mpc_sub(z, tmpa, tmpb); // z - (xt + zt); mpc_add(y, tmpb, tmpc); // z - (xt + zt) + y; mpc_add(x, tmpc, yt); // yt := z - (xt + zt) + y + x mpc_sub(yt, p, tmpa); // yt - p mpc_abs(tmpa, tmpaf); // |yt - p| if not s_mpf_is0(tmpaf) then begin // 分母ゼロ回避 mpc_inv(tmpa, a); // a = 1 / (yt - p) end else begin mpc_set_dbl(a, 1E200, 0); ERRF := ERRF or 4; end; mpc_sub(yt, xt, tmpa); // yt - xt mpc_sub(zt, yt, tmpb); // zt - yt mpc_mul(a, tmpa, tmpc); // a * (yt - xt) mpc_mul(tmpc, tmpb, b); // b = a * (yt - xt) * (zt - yt) mpc_add(yt, b, pt); // pt = yt + b mpc_abs(yt, tmpaf); // |yt| if not s_mpf_is0(tmpaf) then begin // 分母ゼロ回避 mpc_mul(xt, zt, tmpa); // xt * zt; mpc_div(tmpa, yt, rho); // rho = xt * zt / yt mpc_mul(p, pt, tmpb); // p * pt mpc_div(tmpb, yt, tau); // tau := p * pt / yt end else begin mpc_set_dbl(rho, 1E200, 0); mpc_set_dbl(tau, 1E200, 0); ERRF := ERRF or 16 + 1; end; rcd(rho, tau, rcx); // rcx := rc(rho, tau); end; mpc_add(pt, pt, tmpa); // 2pt mpc_add(tmpa, zt, tmpb); // zt + 2pt mpc_add(tmpb, yt, tmpa); // yt + zt + 2pt mpc_add(tmpa, xt, tmpb); // xt + yt + zt + 2pt mpc_div(tmpb, d5, A0); // A0 = (xt + yt + zt + 2pt) / 5 mpc_copy(A0, Am); // Am = A0 mpc_sub(pt, xt, tmpa); // pt - xt mpc_sub(pt, yt, tmpb); // pt - yt mpc_sub(pt, zt, tmpc); // pt - zt mpc_mul(tmpa, tmpb, tmpd); // ( pt - xt) * (pt - yt) mpc_mul(tmpd, tmpc, delta); // delta = ( pt - xt) * (pt - yt) * pt - zt mpf_set_dbl(tmpaf, r / 4); // r / 4 mpf_set_dbl(tmpbf, -1 / 6); // -1 / 6 mpf_expt(tmpaf, tmpbf, tmpcf); // (r / 4)^(-1 / 6) mpc_sub(A0, xt, tmpa); // A0 - xt mpc_sub(A0, yt, tmpb); // A0 - yt mpc_sub(A0, zt, tmpc); // A0 - yz mpc_sub(A0, pt, tmpd); // A0 - pt maxc4d(tmpa, tmpb, tmpc, tmpd, tmpa); // Max(?????) mpc_abs(tmpa, tmpaf); // |Max(?????)| mpf_mul(tmpcf, tmpaf, Q); // Q = (r / 4)^(-1 / 6) * |Max(?????)| m := 0; repeat mpc_sqrt(xt, sqrtx); // √x mpc_sqrt(yt, sqrty); // √y mpc_sqrt(zt, sqrtz); // √z mpc_sqrt(pt, sqrtp); // √p mpc_add(sqrty, sqrtz, tmpa); // √y + √z mpc_mul(tmpa, sqrtx, tmpb); // (√y + √z) * √x mpc_mul(sqrty, sqrtz, tmpc); // √y * √z mpc_add(tmpb, tmpc, lamda); // lamda = (√y + √z) * √x + √y * √z mpc_add(sqrtp, sqrtx, tmpa); // √p - √x mpc_add(sqrtp, sqrty, tmpb); // √p - √y mpc_add(sqrtp, sqrtz, tmpc); // √p - √z mpc_mul(tmpa, tmpb, tmpd); // (√p - √x)(√p - √y) mpc_mul(tmpd, tmpc, dm); // dm = (√p - √x)(√p - √y)(√p - √z) mpc_set_dbl(tmpa, -3 * m, 0); // (-3m, 0i) mpc_pow(d4, tmpa, p4); // 4^(-3m, 0i) mpc_abs(dm , tmpaf); if not s_mpf_is0(tmpaf) then begin // ゼロで除算回避 mpc_mul(p4, delta, tmpa); // 4^(-3m, 0i) * δ mpc_div(tmpa, dm, tmpb); // 4^(-3m, 0i) * δ / dm mpc_div(tmpb, dm, em); // em = 4^(-3m, 0i) * δ / dm / dm end else begin mpc_set_dbl(em, 2E200, 0); ERRF := ERRF or 16 + 2; end; mpc_add(one, em, tmpa); // 1 + em rcd(one, tmpa, tmpb); // rc(1, 1+ em) mpc_set_dbl(tmpc, -m, 0); // -m mpc_pow(d4, tmpc, p4); // 4^-m mpc_mul(p4, tmpb, tmpd); // 4^-m * rc(1 + em); if not s_mpf_is0(tmpaf) then begin // ゼロで除算回避 mpc_div(tmpd, dm, def); // def = 4^-m / dm * rc(1 + em) end else begin mpc_set_dbl(def, 1E200, 0); ERRF := ERRF or 16 + 4; end; mpc_add(sum, def, sum); // sum = sum + 4^-m / dm * rc(1 + em) mpc_add(Am, lamda, tmpd); // Am + lamda mpc_div(tmpd, d4, Am); // Am = (Am + lamda) / 4 mpc_add(xt, lamda, tmpd); // xt + lamda mpc_div(tmpd, d4, xt); // xt = (xt + lamda) / 4 mpc_add(yt, lamda, tmpd); // yt + lamda mpc_div(tmpd, d4, yt); // yt = (yt + lamda) / 4 mpc_add(zt, lamda, tmpd); // zt + lamda mpc_div(tmpd, d4, zt); // zt = (zt + lamda) / 4 mpc_add(pt, lamda, tmpd); // pt + lamda mpc_div(tmpd, d4, pt); // pt = (pt + lamda) / 4 m := m + 1; mpc_set_dbl(tmpa, -m, 0); // (-m, 0i) mpc_pow(d4, tmpa, p4); // 4^(-3m, 0i) mpc_abs(p4, tmpbf); // |4^(-3m, 0i)| mpf_mul(tmpbf, Q, tmpaf); // |4^(-3m, 0i)| * Q mpc_abs(Am, tmpcf); // |Am| until mpf_is_lt(tmpaf, tmpcf); // |4^(-3m, 0i)| * Q < |Am| mpc_set_dbl(tmpa, m, 0); // (m, 0i) mpc_pow(d4, tmpa, p4); // 4^(3m, 0i) mpc_mul(p4, Am, tmpd); // 4^(3m, 0i) * Am mpc_sub(A0, x, tmpb); // A0 - x mpc_div(tmpb, tmpd, X0); // X0 = (A0 - x) / 4^3m / Am mpc_sub(A0, y, tmpb); // A0 - y mpc_div(tmpb, tmpd, Y0); // Y0 = (A0 - y) / 4^3m / Am mpc_sub(A0, z, tmpb); // A0 - z mpc_div(tmpb, tmpd, Z0); // Z0 = (A0 - z) / 4^3m / Am mpc_chs(X0, tmpa); // -X0 mpc_sub(tmpa, Y0, tmpb); // -X0 - Y0 mpc_sub(tmpb, Z0, tmpc); // -X0 - Y0 - Z0 mpc_div(tmpc, d2, P0); // P0 = (-X0 - Y0 - Z0) / 2 mpc_sub(A0, y, tmpb); // A0 - y mpc_mul(X0, Y0, tmpa); // X0 * Y0 mpc_mul(X0, Z0, tmpb); // X0 * Z0 mpc_mul(Y0, Z0, tmpc); // Y0 * Z0 mpc_add(tmpa, tmpb, tmpd); // X0 * Y0 + X0 * Z0 mpc_add(tmpc, tmpd, tmpa); // X0 * Y0 + X0 * Z0 + Y0 * Z0 mpc_mul(P0, P0, tmpb); // P0 * p0 mpc_mul(tmpb, d3, tmpc); // 3 * P0 * p0 mpc_sub(tmpa, tmpc, E2); // E2 = X0 * Y0 + X0 * Z0 + Y0 * Z0 - 3 * P0 * p0 mpc_mul(X0, Y0, tmpa); // X0 * Y0 mpc_mul(tmpa, Z0, tmpb); // X0 * Y0 * Z0 mpc_mul(E2, P0, tmpa); // E2 * P0 mpc_mul(tmpa, d2, tmpc); // 2 * E2 * P0 mpc_mul(P0, P0, tmpa); // P0 * P0 mpc_mul(tmpa, P0, tmpd); // P0 * P0 * p0 mpc_mul(tmpd, d4, tmpa); // 4 * P0 * P0 * p0 mpc_add(tmpb, tmpc, tmpd); // X0 * Y0 * Z0 + 2 * E2 * P0 mpc_add(tmpd, tmpa, E3); // E3 = X0 * Y0 * Z0 + 2 * E2 * P0 + 4 * P0 * P0 * p0 mpc_abs(P0, Pm); // |P0| if not s_mpf_is0(Pm) then begin // |P0| <> 0 // 分母ゼロ回避 mpc_mul(P0, P0, tmpa); // P0 * P0 mpc_mul(tmpa, P0, tmpb); // tmpb P0 * P0 * P0 mpc_mul(tmpb, d3, tmpa); // tmpa 3 * P0 * P0 * P0 mpc_mul(E2, P0, tmpb); // tmpb E2 * P0 mpc_mul(X0, Y0, tmpc); // tmpc X0 * Y0 mpc_mul(tmpc, Z0, tmpd); // tmpd X0 * Y0 * Z0 mpc_mul(tmpd, d2, tmpc); // tmpc 2 * X0 * Y0 * Z0 mpc_add(tmpc, tmpb, tmpd); // tmpd = tmpc + tmpb 2 * X0 * Y0 * Z0 + E2 * P0 mpc_add(tmpd, tmpa, tmpb); // tmpb = tmpd + tmpa 2 * X0 * Y0 * Z0 + E2 * P0 + 3 * P0 * P0 * P0 mpc_div(tmpb, P0, E4); // E4 = tmpb / po 2 * X0 * Y0 * Z0 + E2 * P0 + 3 * P0 * P0 * P0 / P0 end else begin mpc_set_dbl(E4, 0, 0); // P0がゼロの時は誤差が小さくなっているで問題なし // ERRF := ERRF or 16 + 8; end; mpc_mul(X0, Y0, tmpa); // X0 * Y0 mpc_mul(tmpa, Z0, tmpb); // X0 * Y0 * Z0 mpc_mul(tmpb, P0, tmpc); // X0 * Y0 * Z0 * P0 mpc_mul(tmpc, P0, E5); // E5 = X0 * Y0 * Z0 * P0 * P0 mpc_set_dbl(tmpb, -m, 0); // -m, 0i mpc_pow(d4, tmpb, P4); // p4 = d4^-m mpc_set_dbl(tmpc, -3 / 2, 0); // -3 / 2, 0i mpc_pow(Am, tmpc, powa); // Am^(-3 / 2) mpc_mul(c1, E2, tmpa); // c1 * E2 mpc_sub(one, tmpa, def); // 1 - c1 * E2 mpc_mul(c2, E3, tmpb); // c2 * E3 mpc_add(def, tmpb, tmpc); // 1 - c1 * E2 + c2 * E3 mpc_mul(E2, E2, tmpb); // E2 * E2 mpc_mul(c3, tmpb, tmpd); // c3 * E2 * E2 mpc_add(tmpd, def, tmpa); // 1 - c1 * E2 + c2 * E3 + c3 * E2 * E2 mpc_mul(c4, E4, tmpb); // c4 * E4 mpc_mul(E2, E3, tmpc); // E2 * E3 mpc_mul(c5, tmpc, tmpd); // c5 * E2 * E3 mpc_sub(tmpa, tmpb, tmpc); // 1 - c1 * E2 + c2 * E3 + c3 * E2 * E2 - c4 * E4 mpc_sub(tmpc, tmpd, tmpa); // 1 - c1 * E2 + c2 * E3 + c3 * E2 * E2 - c4 * E4 - c5 * E2 * E3 mpc_mul(c6, E5, tmpb); // c6 * E5 mpc_add(tmpa, tmpb, def); // def = 1 - c1*E2 + c2*E3 + c3*E2*E2 - c4*E4 - c5*E2*E3 + c6*E5 mpc_mul(d6, sum, tmpa); // 6 * sum mpc_mul(powa, def, tmpb); // powa * def mpc_mul(tmpb, p4, tmpc); // d4^-m * powa * def mpc_add(tmpc, tmpa, rj); // rj = d4^-m * powa * def + 6 * sum if test < 0 then begin rfd(xt, yt, zt, tmpa); // rf(xt, yt, zt) mpc_sub(rcx, tmpa, tmpb); // rcx - rf(xt, yt, zt) mpc_mul(d3, tmpb, tmpc); // 3 * (rcx - rf(xt, yt, zt)) mpc_mul(b, rj, tmpd); // b * rj mpc_add(tmpc, tmpd, tmpa); // b * rj + 3 * (rcx - rf(xt, yt, zt)) mpc_mul(a, tmpa, rj); // rj = a * (b * rj + 3 * (rcx - rf(xt, yt, zt))) end; mpc_copy(rj, ans); EXT: mpc_clear(one); mpc_clear5(rj, xt, yt, zt, pt); mpc_clear5(sum, a, b, rho, A0); mpc_clear4(tau, rcx, lamda, Am); mpc_clear4(sqrtx, sqrty, sqrtz, sqrtp); mpc_clear3(dm, em, delta); mpc_clear3(c1, c2, c3); mpc_clear3(c4, c5, c6); mpc_clear4(X0, Y0, Z0, P0); mpc_clear4(E2, E3, E4, E5); mpc_clear5(d0, d2, d3, d4, d5); mpc_clear4(d6, p4, powa, def); mpc_clear4(tmpa, tmpb, tmpc, tmpd); mpf_clear3(tmpaf, tmpbf, tmpcf); mpf_clear2(Q, pm); end; // ---------------- Elliptic intehral Calc ------------------------------------- // 楕円積分計算 procedure TForm1.calc_Third_elliptic_integral_complex; label Ext; var kmax : double; c, mc, qc : mp_complex; rf0, rj0 : mp_complex; rft, rjt : mp_complex; afk, ek, fk, kc : mp_complex; tc1, tcm : mp_complex; tca, ac, one : mp_complex; tmpa, tmpb, d3 : mp_complex; tmpaf, tmpbf : mp_float; qmax : double; xc, ans : mp_complex; mdeg, ma, mk : mp_float; mq, mx, mm : mp_float; Intf : integer; k1x1F : boolean; a1x1F : boolean; // 第二種積分 procedure rinteg2(var ans: mp_complex); begin mpc_sub(c, one, tc1); // c - 1 mpc_sub(c, mc, tcm); // c - m RFd(tc1, tcm, c, rf0); RJd(tc1, tcm, c, c, rj0); mpc_mul(mc, rj0, tmpa); // m * rj mpc_div(tmpa, d3, tmpb); // m * rj / 3 mpc_sub(rf0, tmpb, ans); // ans = rf - rj / 3 end; // 第一三種積分 procedure rinteg3(ac: mp_complex; var ans: mp_complex); begin mpc_sub(c, one, tc1); // c - 1 mpc_sub(c, mc, tcm); // c - m mpc_sub(c, ac, tca); // c - a RFd(tc1, tcm, c, rf0); RJd(tc1, tcm, c, tca, rj0); mpc_mul(ac, rj0, tmpa); // a * rj mpc_div(tmpa, d3, tmpb); // a * rj / 3 mpc_add(rf0, tmpb, ans); // ans = rf + a * rj / 3 end; begin mpc_init3(c, mc, qc); mpc_init2(rf0, rj0); mpc_init2(rft, rjt); mpc_init3(afk, ek, fk); mpc_init2(tc1, tcm); mpc_init3(tca, ac, one); mpc_init3(tmpa, tmpb, d3); mpf_init3(tmpaf, tmpbf, mm); mpc_init3(xc, kc, ans); mpf_init5(mdeg, ma, mk, mq, mx); // データー入力 エラーが有ったら終了 if not datainput(ac, xc, kc) then goto Ext; ERRF := 0; ZeroF := 0; mpc_set_dbl(one, 1, 0); mpc_set_dbl(d3, 3, 0); mpc_mul(kc, kc, mc); mpf_set_int(tmpaf, 1); qmax := pi / 2; if mpf_is_gt(mc.re, tmpaf) then begin // パラメータm ,k が1より大きかったら mpf_copy(kc.re, tmpaf); // k mpf_inv(tmpaf, tmpbf); // 1/k mpf_arcsin(tmpbf, tmpaf); // sin^-1(1/k) qmax := abs(mpf_todouble(tmpaf)) end; Edit1.Text := '0'; Edit3.Text := '0'; Edit5.Text := '0'; Edit2.Text := ''; Edit4.Text := ''; Edit6.Text := ''; mpc_abs(xc, tmpbf); // |xc| // 積分範囲がゼロだったら終了 if s_mpf_is0(tmpbf) then goto Ext; kmax := 1 / sin(qmax); // 実数積分角度位置での最大離心率計算 Memo1.Clear; Memo1.Lines.Append('実数積分角度 = ' + floatTostr(qmax / pi * 180) + '°'); Memo1.Lines.Append('最大離心率 = ±' + floatTostr(kmax)); mpf_set1(tmpaf); if mpf_is_le(tmpbf, tmpaf) then begin mpc_inv(xc, tmpa); kmax := mpf_todouble(tmpa.re); Memo1.Lines.Append('指定角度の最大離心率 = ±' + floatTostr(kmax)); end; mpc_mul(xc, xc, tmpb); // xc^2 mpc_inv(tmpb, c); // c = 1 / xc^2 Intf := 0; // ∞フラグ mpf_abs(xc.re, tmpaf); mpf_abs(kc.re, tmpbf); // x = 1 k = 1 check フラグセット if mpf_is1(tmpaf) and mpf_is0(xc.im) and mpf_is1(tmpbf) and mpf_is0(kc.im) then k1x1F := true else k1x1F := False; // x = 1 a = 1 check フラグセット if mpf_is1(tmpaf) and mpf_is0(xc.im) and mpf_is1(ac.re) and mpf_is0(ac.im) then a1x1F := true else a1x1F := False; if k1x1f or a1x1f then begin mpc_set_dbl(afk, maxdouble, 0); // 第三種∞ Intf := Intf or 1; end else begin rinteg3(ac, afk); // 第三種積分 end; mpf_copy(afk.im, tmpaf); // 虚数部が1E-55より小さかったら0に mpf_abs(tmpaf, tmpbf); mpf_set_dbl(tmpaf, 1E-55); if mpf_is_lt(tmpbf, tmpaf) then mpf_set0(afk.im); if not s_mpf_is_ge0(xc.re) then mpc_chs(afk, afk); // 積分範囲が-だったら符号反転 if Intf and 1 = 0 then Edit1.Text := string(mpf_decimal_alt(afk.re, 50)) // 第三種 実数部出力 else begin if s_mpf_is_ge0(xc.re) then Edit1.Text := '∞' else Edit1.Text := '-∞'; end; if k1x1F then begin // k = 1 and x = 1 mpc_set_dbl(ek, 1, 0); // 第二種 1 end else begin rinteg2(ek); // 第二種積分 end; mpf_copy(ek.im, tmpaf); // 虚数部が1E-55より小さかったら0に mpf_abs(tmpaf, tmpbf); mpf_set_dbl(tmpaf, 1E-55); if mpf_is_lt(tmpbf, tmpaf) then mpf_set0(ek.im); if not s_mpf_is_ge0(xc.re) then mpc_chs(ek, ek); // 積分範囲が-だったら符号反転 Edit3.Text := string(mpf_decimal_alt(ek.re, 50)); // 第二種種 実数部出力 if k1x1F then begin // k = 1 and x = 1 mpc_set_dbl(fk, maxdouble, 0); // 第一種∞ Intf := Intf or 2; end else begin mpc_set_dbl(ac, 0, 0); // acにゼロセット rinteg3(ac, fk); // 第一種積分 end; mpf_copy(fk.im, tmpaf); // 虚数部が1E-55より小さかったら0に mpf_abs(tmpaf, tmpbf); mpf_set_dbl(tmpaf, 1E-55); if mpf_is_lt(tmpbf, tmpaf) then mpf_set0(fk.im); if not s_mpf_is_ge0(xc.re) then mpc_chs(fk, fk); // 積分範囲が-だったら符号反転 if Intf and 2 = 0 then Edit5.Text := string(mpf_decimal_alt(fk.re, 50)) // 第一種 実数部出力 else begin if s_mpf_is_ge0(xc.re) then Edit5.Text := '∞' else Edit5.Text := '-∞'; end; if Intf and 1 = 0 then Edit2.Text := string(mpf_decimal_alt(afk.im, 50) + 'i'); // 第三種 虚数部出力 Edit4.Text := string(mpf_decimal_alt(ek.im, 50) + 'i'); // 第二種 虚数部出力 if Intf and 2 = 0 then Edit6.Text := string(mpf_decimal_alt(fk.im, 50) + 'i'); // 第一種 虚数部出力 if ERRF <> 0 then Form1.Memo1.Lines.Append('RJ ゼロでの除算あり code=' + intTostr(ERRF)); if ZeroF and 1 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RCで 引数 y=0 がありました。'); if ZeroF and 2 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RFで 引数 ゼロが二個 がありました。'); if ZeroF and 4 <> 0 then Memo1.Lines.Text := Memo1.Lines.Text + (#13#10 + 'RJで 引数 ゼロが二個 がありました。'); Ext: mpc_clear3(c, mc, qc); mpc_clear2(rf0, rj0); mpc_clear2(rft, rjt); mpc_clear3(afk, ek, fk); mpc_clear2(tc1, tcm); mpc_clear3(tca, ac, one); mpc_clear3(tmpa, tmpb, d3); mpf_clear3(tmpaf, tmpbf, mm); mpc_clear3(xc, kc, ans); mpf_clear5(mdeg, ma, mk, mq, mx); end; // ---------------- 入力処理 --------------------------------------------------- var XF: boolean; // 角度入力、範囲入力 選択フラグ // データの入力 // ac 第三種楕円積分特性値 n // xc 積分範囲 // kc 離心率 function TForm1.datainput(var ac, xc, kc: mp_complex): boolean; label Ext; var FI : boolean; ch, l : integer; a, k, degr, degi : double; m : double; qc : mp_complex; kstr, kss : string; c : char; mdeg, mdegi, tmpaf, tmpbf : mp_float; mq, mk, mx, ma : mp_float; begin result := False; FI := False; val(LabeledEdit1.Text, a, ch); if ch <> 0 then begin application.MessageBox('a(特性)の値に間違いがあります。','a(特性)',0); exit; end; val(LabeledEdit2.Text, degr, ch); if ch <> 0 then begin application.MessageBox('φ(deg)の値に間違いがあります。','φ(deg)',0); exit; end; if abs(degr) > 90 then begin application.MessageBox('φ(deg)の絶対値値は90°迄です。','φ(deg)',0); exit; end; val(LabeledEdit5.Text, degi, ch); if ch <> 0 then begin application.MessageBox('φ(deg)iの値に間違いがあります。','φ(deg)',0); exit; end; if (abs(degr) < 90) and (degi <> 0) then begin application.MessageBox('φ(deg)が90°以下の場合φ(deg)iの値はゼロです。','φ(deg)',0); exit; end; if (degr * degi > 0) and (abs(degr) >= 90) then begin application.MessageBox('φ(deg)とφ(deg)iの符号は±を逆にして下さい','φ(deg)',0); exit; end; if radiobutton1.Checked = true then begin kstr := LabeledEdit3.Text; l := length(kstr); // 文字の長さ取得 c := kstr[l]; // iの文字確認 if (c = 'i') or (c = 'I') then begin // i虚数指定だったら kss := copy(kstr, 1, l - 1); // iの前までコピー FI := true; // 虚数フラグセット end else Kss := kstr; val(kss, k, ch); // kss 数値確認 if ch <> 0 then begin application.MessageBox('k(離心率)の値に間違いがあります。','k(離心率)',0); exit; end; end; if radiobutton2.Checked = true then begin val(LabeledEdit6.Text, m, ch); if ch <> 0 then begin application.MessageBox('mの値に間違いがあります。','m=k^2',0); exit; end; if m < 0 then FI := true; // 虚数フラグセット end; mpc_init(qc); mpf_init4(mdeg, mdegi, tmpaf, tmpbf); mpf_init4(mq, mx, mk, ma); mpf_set0(tmpaf); mpf_read_decimal(ma, PAnsiChar(ansistring(LabeledEdit1.Text + #00))); // a mpc_set_mpf(ac, ma, tmpaf); if radiobutton2.Checked = true then begin mpf_read_decimal(mk, PAnsiChar(ansistring(LabeledEdit6.Text + #00))); // m mpf_abs(mk, mk); // |m| mpf_sqrt(mk, mk); // √m end; if radiobutton1.Checked = true then begin mpf_read_decimal(mk, PAnsiChar(ansistring(kss))); // k string -> mk mp_float end; if FI then mpc_set_mpf(kc, tmpaf, mk) // 虚数だったら kc=(0, mki) else mpc_set_mpf(kc, mk, tmpaf); // 実数だったら kc=(mk, 0i) if not XF then begin mpf_read_decimal(mdeg, PAnsiChar(ansistring(LabeledEdit2.Text + #00))); mpf_div_dbl(mdeg, 180, tmpaf); // mdeg / 180 mpf_set_pi(tmpbf); // pi mpf_mul(tmpaf, tmpbf, mdeg); // mdeg = mdeg / 180 * pi mpf_read_decimal(mdegi, PAnsiChar(ansistring(LabeledEdit5.Text + #00))); mpf_div_dbl(mdegi, 180, tmpaf); // degi / 180 mpf_mul(tmpaf, tmpbf, mdegi); // mdegi = mdei / 180 * pi mpc_set_mpf(qc, mdeg, mdegi); mpc_sin(qc, xc); // sin(qc) LabeledEdit4.Text:= string(mpf_decimal_alt(xc.re, 50)); mpf_set0(xc.im); end else begin mpf_read_decimal(mx, PAnsiChar(ansistring(LabeledEdit4.Text + #00))); mpf_set0(tmpaf); mpc_set_mpf(xc, mx, tmpaf); end; result := true; mpc_clear(qc); mpf_clear4(mdeg, mdegi, tmpaf, tmpbf); mpf_clear4(mq, mx, mk, ma); end; // 角度入力 procedure TForm1.Button1Click(Sender: TObject); begin Button1.Enabled := False; XF := False; calc_Third_elliptic_integral_complex; Button1.Enabled := True; end; // Xの値入力 procedure TForm1.Button2Click(Sender: TObject); var x : double; ch : integer; mx , tmpaf, tmpbf: mp_float; mxc, mcq : mp_complex; begin val(LabeledEdit4.Text, x, ch); if ch <> 0 then begin application.MessageBox('Xの値に間違いがあります。','X',0); exit; end; Button2.Enabled := False; mpf_init3(mx, tmpaf, tmpbf); mpc_init2(mxc, mcq); XF := True; mpf_read_decimal(mx, PAnsiChar(ansistring(LabeledEdit4.Text + #00))); mpf_set0(tmpaf); mpc_set_mpf(mxc, mx, tmpaf); mpc_arcsin(mxc, mcq); mpf_set_pi(tmpaf); mpf_div(mcq.re, tmpaf, tmpbf); // xc.re / pi mpf_mul_dbl(tmpbf, 180, mx); // xc.re / pi * 180 LabeledEdit2.Text:= string(mpf_decimal_alt(mx, 50)); mpf_div(mcq.im, tmpaf, tmpbf); // xc.re / pi mpf_mul_dbl(tmpbf, 180, mx); // xc.re / pi * 180 LabeledEdit5.Text:= string(mpf_decimal_alt(mx, 50)); calc_Third_elliptic_integral_complex; mpf_clear3(mx, tmpaf, tmpbf); mpc_clear2(mxc, mcq); Button2.Enabled := True; end; end.
elliptic_integral_complex.zip
各種プログラム計算例に戻る