2024/9/27
計算範囲の拡大と若干の高速化
デバックに可成り時間を取られましたが、未だ不完全です。
超幾何関数 (Hypergeometric function)
ガウスの超幾何関数
(x)n はポッホハマー記号で表した昇冪 (x)0 = 1、(x)n = x (x+1) (x+2)…(x+n−1)
値は、プログラムを組んで、n=0、n=1、n=2、と順に計算Σ値を求めて、Σ値が変化しなくなるまで計算することで、簡単に求める事が出来ます。
超幾何関数は、初期関数や特殊関数を含んでいます。
しかし、前記の超幾何関数の式では、zの値が1以下でないと収束しません。
cの値が負の整数であると、±∞になり、a或いはbの値が負の整数であればZEROになります。
zの値が1を超える場合は、線形接続公式が必用です。
線形接続公式は数種類あり、zの値に応じて、適切に使用すれば、高速に計算が可能ですが、今回は二種類程度にし、変換計算を使用してみました。
a,b,cの値によって、Γ値、或いは2F1(a,b;c;z)のcの値が0又は負の整数になることがあり、正しく計算されない場合があります。
インターネットで、情報を探しても殆どの論文やレポートは、無限大になる値を避けています。
*インターネットで検索する場合、日本語ではなく、英文で検索することをお勧めします。*
上記の線形接続公式では、Γ(x)のxの値が0(ZERO)或いは0以下の整数であると、Γ値が±∞になり正しい値を返さないことになります。
tan-1に関しては、正しい答えを返すことになります。
tan-1、の時X=1の値に関しては収束しないので、計算出来ません。
又、1に近い値の場合は、収束に時間が掛かり、実際の計算に使用するのには、不向きの様です。
一応プログラムを作成してみました。
左図の演算桁数は、演算上の有効桁数で、答えの有効桁数ではありません。
arctan。arcsinの計算時、1の値に関しては、1の値及びその近傍の値を避ける為、arctan、arcsinにそれぞれ変換して計算しています。
線形接続公式を使用する場合で、Γ値が±∞になる場合、a、b、cの値を少しずらして近似値を計算していますので、正しい結果が出るとは限りませんが有効桁数25桁位はあっていると思われます。(正解の確認が取れません)
Γ値が±∞をとる場合でも、無限大では無く、出来る限り大きい値を設定して計算しているので正しく答えが出る場合もあります。
プログラム
デバッグは、不完全です注意してください。(余りにも大変なので打ち切りました。)
プログラムには、多倍長演算が組み込んであります。
組み込み方は第1種ケルビン関数を参照して下さい。
// Gaussの超幾何関数 // 値が1より小さい場合は必ず収束しますが // 1の場合は専用の計算があります、a又はbの値が負数の整数の場合は収束します。 // 1より大きい場合は、線形接続公式を計算しますが、計算は難しくなります。 // Zの値により、収束の速い線形接続公式を利用すれば良いのですが、ここでは。 // 二種類に限定しています。 // arctan(x)はxの値が1より大きくても必ず正しい値をかえします。 // Z > 1の場合Γ(x)関数を使用するのですが、xの値が0又は負の整数となると // Γ(x) +∞ or -∞となるので微小値を加減算して整数から外して計算しています。 // +Δと-Δの値を計算し平均値を答えとしています。 // |z|>1でa,b,cの値が整数の場合、或いは、虚数部が0でない場合、線形接続公式を用いても高速に計算出来ない値があります。 // 特にa=b c-a=1(c-b=1)の時は難しくなります。 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, system.UITypes, system.Math; type TForm1 = class(TForm) Memo1: TMemo; aEdit: TLabeledEdit; bEdit: TLabeledEdit; cEdit: TLabeledEdit; zEdit: TLabeledEdit; Button1: TButton; iaEdit: TLabeledEdit; ibEdit: TLabeledEdit; icEdit: TLabeledEdit; izEdit: TLabeledEdit; PrecisionEdit: TLabeledEdit; Label1: TLabel; epsEdit: TLabeledEdit; BitBtn1: TBitBtn; artanBtn: TBitBtn; ArtanedEdit: TLabeledEdit; arsinEdit: TLabeledEdit; arsinBtn: TBitBtn; CheckBox1: TCheckBox; CheckBox2: TCheckBox; CheckBox3: TCheckBox; Button2: TButton; CheckBox4: TCheckBox; CheckBox5: TCheckBox; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure BitBtn1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure artanBtnClick(Sender: TObject); procedure arsinBtnClick(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses mp_real, mp_cmplx, mp_types, mp_base, Velthuis.BigIntegers; const NB = 120; // ベルヌーイ数 配列数 NB + 1 var BM : array of mp_float; // ベルヌーイ数配列 NumeratorString : array[0..NB] of string; // 分子 DenominatorString : array[0..NB] of string; // Γ関数用分母 zero, one, two, three, four : mp_float; pai, maxmpf, infs : mp_float; log_2pis2 : mp_complex; // 最大公約数 ユークリッドの互除法 BigInteger function gcd_BigInteger(x, y: BigInteger): BigInteger; var t : BigInteger; begin while y <> 0 do begin t := x mod y; x := y; y := t; end; result := x; end; // ベルヌーイ数 // Akiyama-Tanigawa algorithm // BigInteger procedure Bernoulli_number_BigInteger; const n = (NB + 1) * 2; var m, j, k : integer; a : array of BigInteger; // 分子 b : array of BigInteger; // 分母 tmpN : BigInteger; // 分子 tmpD : BigInteger; // 分母 gcd : BigInteger; // 最大公約数 b0 : BigInteger; begin setlength(a, n + 1); setlength(b, n + 1); k := 0; for m := 0 to n do begin a[m] := 1; // 分子 初期値 b[m] := (m + 1); // 分母 初期値 for j := m - 1 downto 0 do begin tmpN := a[j] * b[j + 1] - a[j + 1] * b[j]; // 分子 tmpN := tmpN * (j + 1); // 〃 tmpD := b[j] * b[j + 1]; // 分母 gcd := gcd_BigInteger(tmpN, tmpD); // 最大公約数 a[j] := tmpN div gcd; b[j] := tmpD div gcd; end; if (m > 0) and (m mod 2 = 0) then begin b0 := b[0]; // logΓ関数用に分母値Bの値計算 b0 := b0 * m * (m -1); // m ベルヌーイ数No NumeratorString[k] := a[0].tostring; // 分子 DenominatorString[k] := b0.tostring; // Γ関数用分母 inc(k); end; end; end; // ログガンマ多倍長 procedure log_GammaMul(var x, ans : mp_complex); var v, w, cone, ctwo : mp_complex; tmp, tmp0, s : mp_complex; i : integer; begin mpc_init4(v, w, cone, ctwo); mpc_init3(tmp, tmp0, s); mpc_set1(cone); // 1 + 0i mpc_add(cone, cone, ctwo); // 2 + 0i mpc_set1(v); // 1 + 0i mpc_set0(tmp); // 0 + 0i mpf_set_int(tmp.re, NB); // NB + 0i while mpf_is_lt(x.re, tmp.re) do begin // while x < NB do mpc_mul(v, x, v); // v = v * x mpf_add(x.re, one, x.re); // x := x + 1 end; mpc_mul(x, x, tmp); // x^2 mpc_div(cone, tmp, w); // w = 1 / x^2 mpc_set0(s); // s = 0 + 0i for i := NB downto 1 do begin mpc_add_mpf(s, BM[i], tmp); // tmp = s + B[i] mpc_mul(tmp, w, s); // s = tmp * w end; mpc_add_mpf(s, BM[0], tmp); // tmp = s + B[0] mpc_div(tmp, x, s); // s = (s + B[0]) / x mpc_add(s, log_2pis2, s); // s = s + ln(2π)/2 mpc_ln(v, tmp); // ln(v) mpc_sub(s, tmp, s); // s := s - ln(v) mpc_sub(s, x, s); // s := s - x mpc_div(cone, ctwo, tmp); // tmp = 1/2 mpc_sub(x, tmp, tmp0); // tmp0 = x - 1/2 mpc_ln(x, tmp); // ln(x) mpc_mul(tmp0, tmp, tmp0); // tmp0 = (x - 1/2) * ln(x) mpc_add(s, tmp0, ans); // ans = s + (x - 1/2) * ln(x) mpc_clear4(v, w, cone, ctwo); mpc_clear3(tmp, tmp0, s); end; // 多倍長ガンマ 複素数 // xの値が 0 と負整数の時Γは∞になるので∞フラグセット値は1を返します。 function gammaMul(xx : mp_complex; var ans: mp_complex) : integer; label EXT; var tmp, sinx, logG, cone, cpai : mp_complex; x : mp_complex; begin mpc_init5(tmp, sinx, logG, cone, cpai); mpc_init(x); // xxの値を変化させるxxの元値を解放不可になるのでコピーして使用します // mpc_copy(xx, x); mpf_read_decimal(x.re, PAnsiChar(ansistring(string(mpf_decimal(xx.re, 200)) + #00))); mpf_read_decimal(x.im, PAnsiChar(ansistring(string(mpf_decimal(xx.im, 200)) + #00))); // 虚数部がゼロで実数部がゼロを含み負の整数だったら∞ if mpf_is0(x.im) and mpf_is_le(x.re, zero) then begin mpf_frac(x.re, tmp.re); // 実数部の小数点以下取り出し if mpf_is0(tmp.re) then begin // 小数点以下がゼロだったら mpf_copy(maxmpf, ans.re); mpf_div(x.re, two, tmp.re); mpf_frac(tmp.re, tmp.re); if not mpf_is0(tmp.re) then mpf_chs(ans.re, ans.re); // mpf_set_dbl(ans.re, maxdouble); mpf_set0(ans.im); // mpc_set0(ans); result := 1; // ∞フラグセット goto EXT; // 終了 end; end; mpc_set_mpf(cpai, pai, zero); // π+ 0i mpc_set1(cone); // 1 + 0i if mpf_is_lt(x.re, zero) then begin // x.real < 0 mpc_mul_mpf(x, pai, tmp); // x*π mpc_sin(tmp, sinx); // sin(πx); mpc_sub(cone, x, tmp); // 1-x log_GammaMul(tmp, logG); // loggamma(1-x); mpc_exp(logG, logG); // exp(loggamma) mpc_div(cpai, sinx, tmp); // π/sin(πx) mpc_div(tmp, logG, ans); // ans = π/(sin(πx) * logG(1-x)) end else begin // x.real >= 0 log_GammaMul(x, logG); // logGamma(x) mpc_exp(logG, ans); // exp(logGamma) end; result := 0; // 成功フラグ値 EXT: mpc_clear5(tmp, sinx, logG, cone, cpai); mpc_clear(x); end; // x(-0.5, 0) y(1.5, 0) 有効桁数70前後 // x(-0.5, -0.5) y(4, 0) 有効桁数60前後 // x(-0.5, 0.5) y(2, 0) 有効桁数70前後 procedure mpc_powa(x, y : mp_complex; var ans : mp_complex); var ay, ai, zero, harf, two : mp_float; begin mpf_init5(ay, ai, zero, harf, two); mpf_set_int(two, 2); // 2 mpc_pow(x, y, ans); // exp(y*ln(x)) // xの虚数部とyの虚数部0なら if mpf_is0(x.im) and mpf_is0(y.im) then begin mpf_set0(zero); // 0 mpf_inv(two, harf); // 1/2 0.5 mpf_abs(y.re, ay); // yの実数部の絶対値 mpf_frac(ay, ai); // yの実数部の絶対値の小数部 mpf_sub(ai, harf, ai); // yの実数部の絶対値の小数部と0.5の差分 // 差分がゼロ(yの実数部の小数部が0.5) if mpf_is0(ai) then // xの実数部が0と等しいか0より大きいなら if mpf_is_ge(x.re, zero) then mpf_set0(ans.im) // 答えの虚数部0 // 0より小さいなら else mpf_set0(ans.re); // 答えの実数部0 mpf_frac(y.re, ai); // 乗数の小数部 if mpf_is0(ai) then mpf_set0(ans.im); // 整数なら答えの虚数部0 end; // xの整数部とyの虚数部が0なら if mpf_is0(x.re) and mpf_is0(y.im) then begin mpf_frac(y.re, ai); // 乗数の小数部 if mpf_is0(ai) then begin // 整数なら mpf_div(y.re, two, ay); // 偶数奇数確認 mpf_frac(ay, ai); // 小数部 if mpf_is0(ai) then mpf_set0(ans.im) // 偶数なら 虚数部0 else mpf_set0(ans.re); // 奇数なら実数部0 end; end; mpf_abs(x.re, ay); mpf_abs(x.im, ai); // xの実数部と虚数部の絶対値が等しくてyがゼロでなかったら if mpf_is_eq(ay, ai) and mpf_is0(y.im) and not mpc_is0(y) then begin mpf_frac(y.re, ai); // 乗数の小数部 if mpf_is0(ai) then begin // 整数なら mpf_div(y.re, two, ay); // 偶数奇数確認 mpf_frac(ay, ai); // 小数部 if mpf_is0(ai) then begin mpf_add(two, two, two); // 4 mpf_div(y.re, two, ay); // 4偶数奇数確認 mpf_frac(ay, ai); // 小数部 if mpf_is0(ai) then mpf_set0(ans.im) // 偶数なら 虚数部0 y= 4 8 else mpf_set0(ans.re); // 偶数なら 虚数部0 y= 2 6 10 end; end; end; mpf_clear5(ay, ai, zero, harf, two); end; const NC = 10000; var BR : boolean; // 計算打切りフラグ TN : integer; // 計算実行 0 通常 1 artan 2 arsin DS : integer; // 計算表示 0 通常 1 artan 2 arsin procedure comment; var str : string; begin with form1.Memo1 do begin Clear; str := ' ガウスの超幾何関数'; lines.Append(str); str := ' zの値が1に近づくと、収束に時間が掛かります。'; lines.Append(str); str := 'その時にPfaffの変換をすると、収束が速くなるのですが、a,b,cの値に整数であると'; str := str + '正しい答えを返さない場合があります。'; lines.Append(str); str := 'zの値が0.85程度であれば、Pfaffの変換を使用しなくても、結構速く収束するので'; str := str + 'Pfaffの変換のある場合とない場合で同じ答えがでるか確認して下さい。'; lines.Append(str); str := '答えが違う場合は、その時の"a,b,c"値ではPfaffの変換は使用できません。'; lines.Append(str); str := ' 無限大回避は、"z>1"の時Γ関数を使用するのですが、Γ(x)のxの値が"0"又は'; str := str + '負の整数の時±無限大になるのを避ける為のものです。'; lines.Append(str); str := '無限大回避を使用した時と'; str := str + 'しない場合で答えが違う場合は、無限大回避を使用してください。'; lines.Append(str); str := ' Pfaff変換をした場合、計算上"z"の値が1を越え、Γ(x)の計算が使用されます。'; lines.Append(str); str := '無限大回避を使用した場合としない場合で答えが違う場合は、無限大回避を使用してください。'; lines.Append(str); end; end; // ガウスの超幾何関数 z < 1 procedure Hypergeometric_function(a, b, c, z : mp_complex; eps : mp_float; var ans : mp_complex; var n, f : integer); label EXT; var ap, bp, cp, zhn : mp_complex; ah, bh, ch, ab : mp_complex; s, sb, tmp, tmpb : mp_complex; nbig, nk : mp_float; smla, smlb, ftmp : mp_float; dpcs : integer; begin mpc_init4(ap, bp, cp, zhn); mpc_init4(ah, bh, ch, ab); mpc_init4(s, sb, tmp, tmpb); mpf_init2(nbig, nk); mpf_init3(smla, smlb, ftmp); dpcs := mpf_get_default_prec; mpc_set0(s); // 0 mpf_set0(smla); // 0 mpf_set0(smlb); // 0 mpc_copy(s, sb); mpf_set1(nk); // n! = 1 mpc_copy(z, zhn); // n = 1時値セット n=0 は1なので後で加算 mpc_copy(a, ah); // a(a+1)(a+2)(a+n-1) mpc_copy(b, bh); mpc_copy(c, ch); mpc_copy(a, ap); // a+n-1 mpc_copy(b, bp); mpc_copy(c, cp); mpf_set1(nbig); // n = 1 n := 1; // loop数 =1 mpc_set0(tmp); // 計算値初期化 0 repeat // n = 1から計算 mpc_mul(ah, bh, ab); // (a)n * (b)n if mpc_is0(ab) and not mpc_is0(ch) then begin // (a)n * (b)n = 0 ch<>0 なら f := 4; // a*b がゼロフラグセット終了 break; end; if mpc_is0(ch) then begin // (c)n = 0 なら if mpf_is_ge(s.re, zero) then f := 2 // ∞ 無限大フラグセットして終了 else f := 1; // -∞ if mpc_is0(ab) then begin f := 2; mpc_set1(ab); end; mpc_mul(ab, zhn, ans); break; end; mpc_copy(s, sb); mpc_copy(tmp, tmpb); mpc_set0(tmp); // Σ 1~ (a(n)b(n)Z^n)/(c(n)n^n) mpc_div_mpf(ab, nk, tmp); // (a)n * (b)n / n! mpc_mul(tmp, zhn, tmp); // (a)n * (b)n / n! * z^n mpc_div(tmp, ch, tmp); // (a)n * (b)n / n! * z^n / (c)n mpc_add(s, tmp, s); // Σ // form1.memo1.Lines.Append('loop = ' + intTostr(n) + string(' ' + mpf_decimal(tmp.re, 20))); mpf_add(ap.re, one, ap.re); // a = a + 1 mpf_add(bp.re, one, bp.re); // b = b + 1 mpf_add(cp.re, one, cp.re); // c = c + 1 mpc_mul(ah, ap, ah); // a(a+1)(a+2)(a+3)(a+n-1) mpc_mul(bh, bp, bh); // b(b+1)(b+2)(b+3)(b+n-1) mpc_mul(ch, cp, ch); // c(a+1)(c+2)(c+3)(c+n-1) mpc_mul(zhn, z, zhn); // z^n inc(n); // ループカウンターインクリメント mpf_add(nbig, one, nbig); // n = n + 1 mpf_mul(nk, nbig, nk); // n! mpc_abs(tmp, ftmp); if n mod 100 = 0 then begin // 指定回数に途中経過表示 form1.memo1.Lines.Append('loop = ' + intTostr(n) + string(' ' + mpf_decimal(ftmp, 20))); application.ProcessMessages; if BR then begin form1.memo1.Lines.Append('途中停止しました。'); break; end; end; // 収束判定 until (mpf_is_lt(ftmp, eps) or (n >= NC)); if (f = 1) or (f = 2) then else mpc_add_mpf(s, one, ans); // n = 0の値1を加算 form1.memo1.Lines.Append('loop数 = ' + intTostr(n)); EXT: mpc_clear4(ap, bp, cp, zhn); mpc_clear4(ah, bh, ch, ab); mpc_clear4(s, sb, tmp, tmpb); mpf_clear2(nbig, nk); mpf_clear3(smla, smlb, ftmp); end; // z > 1 a = b, c <> a // a = b c <> a 専用ルーチン procedure Hypergeometric_function_of_first_kind_aeb(a, b, c, z : mp_complex; eps : mp_float; var ans : mp_complex; var n, f : integer); label EXT; var ga, gb, gc, gcmamb, gapbmc : mp_complex; ma, amcpone, apbmcpone, cma, onema : mp_complex; onemz, cmamb, chsa, amc, onemonesz : mp_complex; cone, onmzhcab, zhma, tmc : mp_complex; cmb, gcmb, cmambpone, gcma : mp_complex; apbmc, zhamc : mp_complex; fa, fb, g1, g2: mp_complex; afa, afb : mp_complex; f1, f2 : integer; begin mpc_init5(ga, gb, gc, gcmamb, gapbmc); mpc_init5(ma, amcpone, apbmcpone, cma, onema); mpc_init5(onemz, cmamb, chsa, amc, onemonesz); mpc_init5(cone, onmzhcab, zhma, tmc, cmambpone); mpc_init5(cmb, gcmb, gcma, apbmc, zhamc); mpc_init4(fa, fb, g1, g2); mpc_init2(afa, afb); mpc_set1(cone); mpc_sub(c, a, cma); // c-a mpc_sub(cma, b, cmamb); // c-a-b mpc_sub(a, c, amc); // a-c mpc_sub(c, b, cmb); // c-b mpc_add(a, b, tmc); mpc_sub(tmc, c, apbmc); // a+b-c mpc_chs(a, chsa); // -a mpc_sub(cone, z, onemz); // 1-z mpc_add(amc, cone, amcpone); // a-c+1 mpc_add(amc, b, tmc); mpc_add(tmc, cone, apbmcpone); // a+b-c+1 mpc_sub(cone, a, onema); // 1-a mpc_sub(cma, b, tmc); mpc_add(tmc, cone, cmambpone); // c-a-b+1 mpc_inv(z, tmc); mpc_sub(cone, tmc, onemonesz); // 1-1/z gammaMul(a, ga); // Γ(a) gammaMul(b, gb); // Γ(b) gammaMul(c, gc); // Γ(c) gammaMul(cmamb, gcmamb); // Γ(c-a-b) gammaMul(cma, gcma); // Γ(c-a) gammaMul(cmb, gcmb); // Γ(c-b) gammaMul(apbmc, gapbmc); // Γ(a+b-c) mpc_powa(z, chsa, zhma); // z^-a mpc_powa(onemz, cmamb, onmzhcab); // (1-z)^(c-a-b) mpc_powa(z, amc, zhamc); // z~(a-c) mpc_mul(gc, gcmamb, g1); // Γ(c)Γ(c-a-b) mpc_mul(gcma, gcmb, tmc); // Γ(c-a)Γ(c-b) mpc_div(g1, tmc, g1); // g1 =Γ(c)Γ(c-a-b)/(Γ(c-a)Γ(c-b)) mpc_mul(gc, gapbmc, g2); // Γ(c)Γ(a+b-c) mpc_mul(ga, gb, tmc); // Γ(a)Γ(b) mpc_div(g2, tmc, g2); // g2 =Γ(c)Γ(a+b-c)/(Γ(a)Γ(b)) f1 := 0; Hypergeometric_function(a, amcpone, apbmcpone, onemonesz, eps, fa, n, f1); // 2F1(a, a-c+1, a+b-c+1, 1-1/z) f2 := 0; Hypergeometric_function(cma, onema, cmambpone, onemonesz, eps, fb, n, f2); // 2F1(c-a, 1-a, c-a-b+1, 1-1/z) mpc_mul(g1, zhma, tmc); mpc_mul(tmc, fa, afa); // A1 mpc_mul(g2, onmzhcab, tmc); mpc_mul(tmc, zhamc, tmc); mpc_mul(tmc, fb, afb); // A2 mpc_add(afa, afb, ans); // ans = A1 + A2 if f1 <> 0 then f := f1; if f2 <> 0 then f := f2; mpc_clear5(ga, gb, gc, gcmamb, gapbmc); mpc_clear5(ma, amcpone, apbmcpone, cma, onema); mpc_clear5(onemz, cmamb, chsa, amc, onemonesz); mpc_clear5(cone, onmzhcab, zhma, tmc, cmambpone); mpc_clear5(cmb, gcmb, gcma, apbmc, zhamc); mpc_clear4(fa, fb, g1, g2); mpc_clear2(afa, afb); end; // z > 1 procedure Hypergeometric_function_of_first_kind(a, b, c, amb, bma, cma, cmb, aeb, z : mp_complex; eps : mp_float; var ans : mp_complex; var n, f : integer); label EXT; var ga, gb, gc, gamb, gbma : mp_complex; gcma, gcmb, mzhma, mzhmb, mz : mp_complex; onepamc, onepbmc, onepamb, onemapb : mp_complex; ma, mb, sa, sb, tmc : mp_complex; onesz, fa, fb : mp_complex; f1, f2 : integer; begin // if mpc_is0(a) or mpc_is0(b) then begin // mpc_set1(ans); // exit; // end; mpc_init5(ga, gb, gc, gamb, gbma); mpc_init5(gcma, gcmb, mzhma, mzhmb, mz); mpc_init4(onepamc, onepbmc, onepamb, onemapb); mpc_init5(ma, mb, sa, sb, tmc); mpc_init3(onesz, fa, fb); gammaMul(a, ga); // Γ(a) gammaMul(b, gb); // Γ(b) gammaMul(c, gc); // Γ(c) gammaMul(amb, gamb); // Γ(a-b) gammaMul(bma, gbma); // Γ(b-a) gammaMul(cma, gcma); // Γ(c-a) gammaMul(cmb, gcmb); // Γ(c-b) mpc_chs(z, mz); // -z mpc_chs(a, ma); // -a mpc_chs(b, mb); // -b mpc_powa(mz, ma, mzhma); // (-z)^-a mpc_powa(mz, mb, mzhmb); // (-z)^-b mpc_set1(tmc); // mpc_sub(tmc, cma, onepamc); // 1+a-c mpc_sub(tmc, cmb, onepbmc); // 1+b-c mpc_add(tmc, amb, onepamb); // 1+a-b mpc_add(tmc, bma, onemapb); // 1-a+b mpc_inv(z, onesz); // 1/z Hypergeometric_function(a, onepamc, onepamb, onesz, eps, sa, n, f1); // 2F1(a, 1+a-c. 1+a-b, 1/z) form1.memo1.Lines.Append('loop = ' + intTostr(n) + string(' ' + mpf_decimal(sa.re, 20))); form1.memo1.Lines.Append(' ' + string(' ' + mpf_decimal(sa.im, 20)) + ' i'); // BR := false; // 割込みフラグ解除 Hypergeometric_function(b, onepbmc, onemapb, onesz, eps, sb, n, f2); // 2F1(b, 1+b-c, 1-a+b, 1/z) form1.memo1.Lines.Append('loop = ' + intTostr(n) + string(' ' + mpf_decimal(sb.re, 20))); form1.memo1.Lines.Append(' ' + string(' ' + mpf_decimal(sb.im, 20)) + ' i'); mpc_mul(gc, gbma, tmc); // Γ(c) * Γ(b-a) mpc_div(tmc, gb, tmc); // Γ(c) * Γ(b-a) / Γ(b) mpc_div(tmc, gcma, tmc); // Γ(c) * Γ(b-a) / Γ(b) / Γ(c-a) // form1.memo1.Lines.Append(' Γ1 ' + string(' ' + mpf_decimal(tmc.re, 20))); // form1.memo1.Lines.Append(' Γ1 ' + string(' ' + mpf_decimal(tmc.im, 20)) +' i'); mpc_mul(tmc, mzhma, tmc); // Γ(c) * Γ(b-a) / Γ(b) / Γ(c-a) * (-z)^-a mpc_mul(tmc, sa, fa); // Γ(c) * Γ(b-a) / Γ(b) / Γ(c-a) * (-z)^-a * 2F1(a) mpc_mul(gc, gamb, tmc); // Γ(c) * Γ(a-b) mpc_div(tmc, ga, tmc); // Γ(c) * Γ(a-b) / Γ(a) mpc_div(tmc, gcmb, tmc); // Γ(c) * Γ(a-b) / Γ(a) / Γ(c-b) // form1.memo1.Lines.Append(' Γ2 ' + string(' ' + mpf_decimal(tmc.re, 20))); // form1.memo1.Lines.Append(' Γ2 ' + string(' ' + mpf_decimal(tmc.im, 20)) +' i'); mpc_mul(tmc, mzhmb, tmc); // Γ(c) * Γ(a-b) / Γ(a) / Γ(c-b) * (-z)^-b mpc_mul(tmc, sb, fb); // Γ(c) * Γ(a-b) / Γ(a) / Γ(c-b) * (-z)^-b * 2F1(b) mpc_add(fa, fb, ans); // Σ // a = b 時は fa=fbとなり 解はfa 又は fbとなるので1/2にします if mpc_is0(aeb) then mpc_div_mpf(ans, two, ans); if (f1 = 1) or (f1 = 2) then f := 16; if (f2 = 1) or (f2 = 2) then f := 16; EXT: mpc_clear5(ga, gb, gc, gamb, gbma); mpc_clear5(gcma, gcmb, mzhma, mzhmb, mz); mpc_clear4(onepamc, onepbmc, onepamb, onemapb); mpc_clear5(ma, mb, sa, sb, tmc); mpc_clear3(onesz, fa, fb); end; // z=1 超幾何定理計算 procedure Hypergeometric_function_zeq1(a, b, c, z : mp_complex; eps : mp_float; var ans : mp_complex; var n, f : integer); label EXT; var cmamb, cma, cmb, tmp: mp_complex; gc, gcma, gcmb, gcmamb : mp_complex; begin mpc_init4(cmamb, cma, cmb, tmp); mpc_init4(gc, gcma, gcmb, gcmamb); f := 0; n := 0; mpc_sub(c, a, cmamb); // c - a mpc_sub(cmamb, b, cmamb); // c - a - b if mpf_is_le(cmamb.re, zero) then begin // Re(c-a-b) <= 0 f := 8; // ∞±符号計算フラグ mpc_set0(ans); goto EXT; end; // Re(c-a-b) > 0 時の計算 mpc_sub(c, a, cma); mpc_sub(c, b, cmb); gammaMul(c, gc); // Γ(c) gammaMul(cma, gcma); // Γ(c-a) gammaMul(cmb, gcmb); // Γ(c-b) gammaMul(cmamb, gcmamb); // Γ(c-a-b) mpc_mul(gc, gcmamb, tmp); // Γ(c) * Γ(c^a-b) mpc_div(tmp, gcma, tmp); // Γ(c) * Γ(c^a-b) / Γ(c-a) mpc_div(tmp, gcmb, ans); // Γ(c) * Γ(c^a-b) / Γ(c-a) / Γ(c-b) EXT: mpc_clear4(cmamb, cma, cmb, tmp); mpc_clear4(gc, gcma, gcmb, gcmamb); end; // arcsin計算 procedure TForm1.arsinBtnClick(Sender: TObject); var ch : integer; ars : double; tmp0, tmp1, tmp2 : mp_float; begin val(arsinEdit.Text, ars, ch); if ch <> 0 then begin application.MessageBox('arsin の値に間違いがあります。','注意',0); exit; end; if abs(ars) > 1 then begin application.MessageBox('arsin の値は±1迄にして下さい。','注意',0); exit; end; mpf_init3(tmp0, tmp1, tmp2); mpf_read_decimal(tmp0, PAnsiChar(ansistring(arsinEdit.Text + #00))); if (abs(ars) < 0.75) or (abs(ars) = 1) then TN := 2 else TN := 1; aedit.Text := '0.5'; if (abs(ars) < 0.75) or (abs(ars) = 1) then bedit.text := '0.5' else bedit.text := '1'; cedit.text := '1.5'; if (abs(ars) < 0.75) or (abs(ars) = 1) then zedit.text := arsinEdit.Text else begin mpf_mul(tmp0, tmp0, tmp1); // ars * ars mpf_sub(one, tmp1, tmp2); // 1 - ars * ars mpf_sqrt(tmp2, tmp1); // sqrt(1 - ars * ars) mpf_div(tmp0, tmp1, tmp2); // ars / sqrt(1 - ars * ars) // ars := ars / sqrt(1 - ars * ars); zedit.Text := string(mpf_decimal(tmp2, 50)); // zedit.text := floattostr(ars); end; iaedit.Text := '0'; ibedit.text := '0'; icedit.text := '0'; izedit.text := '0'; DS := 2; mpf_clear3(tmp0, tmp1, tmp2); Button1Click(nil); end; // arctan計算 procedure TForm1.artanBtnClick(Sender: TObject); var ch : integer; art : double; tmp0, tmp1, tmp2 : mp_float; begin val(ArtanedEdit.Text, art, ch); if ch <> 0 then begin application.MessageBox('artan の値に間違いがあります。','注意',0); exit; end; mpf_init3(tmp0, tmp1, tmp2); mpf_read_decimal(tmp0, PAnsiChar(ansistring(ArtanedEdit.Text + #00))); if (abs(art) < 0.75) or (abs(art) > 1.4) then TN := 1 else TN := 2; aedit.Text := '0.5'; if (abs(art) < 0.75) or (abs(art) > 1.4) then bedit.text := '1' else bedit.text := '0.5'; cedit.text := '1.5'; if (abs(art) < 0.75) or (abs(art) > 1.4) then zedit.text := artanededit.Text else begin mpf_mul(tmp0, tmp0, tmp1); // art * art mpf_add(tmp1, one, tmp2); // 1 + art * art mpf_sqrt(tmp2, tmp1); // sqrt(1 + art * art) mpf_div(tmp0, tmp1, tmp2); // art / sqrt(1 + art * art) zedit.Text := string(mpf_decimal(tmp2, 50)); end; iaedit.Text := '0'; ibedit.text := '0'; icedit.text := '0'; izedit.text := '0'; DS := 1; mpf_clear3(tmp0, tmp1, tmp2); Button1Click(nil); end; // 計算打切り procedure TForm1.BitBtn1Click(Sender: TObject); begin BR := True; end; // x <= 0 で 整数なら result = true function zeroorounder(xx: mp_complex): boolean; label EXT; var xc : mp_float; x : mp_complex; begin mpf_init(xc); mpc_init(x); // xxの値を変化させるxxの元値を解放不可になるのでコピーして使用します mpc_copy(xx, x); result := false; if not mpf_is0(x.im) then goto EXT; // frac 桁落ち対策 mpf_read_decimal(x.re, PAnsiChar(mpf_decimal(x.re, 200) + #00)); mpf_frac(x.re, xc); if not mpf_is0(xc) then goto EXT; if mpf_is_le(x.re, zero) then result := true; EXT: mpf_clear(xc); mpc_clear(x); end; // 数値の後ろのゼロ消去 function ZeroErase(s : string): string; const EP = 'E'; ZC = '0'; dt = '.'; var c : char; i, j, k, l : integer; begin l := length(s); j := 1; for i := 1 to l do begin c := s[i]; if c = EP then begin j := i - 1; break; end; j := i; end; result := ''; if j < l then begin for i := l downto j + 1 do result := s[i] + result; end; K := 1; for i := j downto 1 do begin c := s[i]; if c <> ZC then begin k := i; if c = DT then k := k + 1; break; end; end; for i := k downto 1 do result := s[i] + result; end; // 計算開始 procedure TForm1.Button1Click(Sender: TObject); label EXT, TN0E, ZG1, ZG2, ZG3; var a, b, c, z, ans : mp_complex; mz2, tans, dat, tmc : mp_complex; ch, n, pre : integer; f : integer; chd, zrd, zid : double; eps, az: mp_float; amb, bma, cma, cmb, aeb : mp_complex; d1, d2, em40 : mp_float; XLE : boolean; ap, bp, cp : mp_complex; am, bm, cm : mp_complex; zback, aback, zbackp : mp_complex; dnine, tmf, em : mp_float; absz : mp_float; df : integer; // 1E-100 以下はゼロにセット procedure zerounde1em100(var ans: mp_complex); begin mpf_read_decimal(d1, PAnsiChar(ansistring('1E-100' + #00))); mpf_abs(ans.re, tmf); if mpf_is_lt(tmf, d1) then mpf_set0(ans.re); mpf_abs(ans.im, tmf); if mpf_is_lt(tmf, d1) then mpf_set0(ans.im); end; begin val(aedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('a の値に間違いがあります。','注意',0); exit; end; val(bedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('b の値に間違いがあります。','注意',0); exit; end; val(cedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('c の値に間違いがあります。','注意',0); exit; end; val(zedit.Text, zrd, ch); if ch <> 0 then begin application.MessageBox('z の値に間違いがあります。','注意',0); exit; end; val(iaedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('a の虚数値に間違いがあります。','注意',0); exit; end; val(ibedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('b の虚数値に間違いがあります。','注意',0); exit; end; val(icedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('c の虚数値に間違いがあります。','注意',0); exit; end; val(izedit.Text, zid, ch); if ch <> 0 then begin application.MessageBox('z の虚数値に間違いがあります。','注意',0); exit; end; val(precisionedit.Text, pre, ch); if ch <> 0 then begin application.MessageBox('有効桁数 の値に間違いがあります。','注意',0); exit; end; if pre < 10 then begin application.MessageBox('有効桁数 は10以上にして下さい。','注意',0); exit; end; val(epsedit.Text, chd, ch); if ch <> 0 then begin application.MessageBox('収束判定値に間違いがあります。','注意',0); exit; end; button1.Enabled := False; BR := false; // 停止フラグリセット mpf_set_default_prec(pre); // 有効桁数セット mpc_init5(a, b, c, z, ans); mpf_init5(eps, az, tmf, em40, em); mpc_init4(mz2, tans, dat, tmc); mpc_init5(amb, bma, cma, cmb, aeb); mpf_init3(d1, d2, dnine); mpc_init4(ap, bp, cp, zbackp); mpc_init5(am, bm, cm, zback, aback); mpf_init(absz); memo1.Clear; memo1.Lines.Append('計算中'); application.ProcessMessages; mpf_read_decimal(a.re, PAnsiChar(ansistring(aedit.Text + #00))); mpf_read_decimal(b.re, PAnsiChar(ansistring(bedit.Text + #00))); mpf_read_decimal(c.re, PAnsiChar(ansistring(cedit.Text + #00))); mpf_read_decimal(z.re, PAnsiChar(ansistring(zedit.Text + #00))); mpf_read_decimal(a.im, PAnsiChar(ansistring(iaedit.Text + #00))); mpf_read_decimal(b.im, PAnsiChar(ansistring(ibedit.Text + #00))); mpf_read_decimal(c.im, PAnsiChar(ansistring(icedit.Text + #00))); mpf_read_decimal(z.im, PAnsiChar(ansistring(izedit.Text + #00))); mpf_read_decimal(eps, PAnsiChar(ansistring(epsedit.Text + #00))); mpf_read_decimal(dnine, PAnsiChar(ansistring('0.83' + #00))); mpf_read_decimal(em, PAnsiChar(ansistring('1E-30' + #00))); mpf_read_decimal(em40, PAnsiChar(ansistring('1E-35' + #00))); // 答え40桁時 ゼロ判定値 // 小数点以下入力制限 if mpf_is0(a.im) then begin mpf_frac(a.re, tmf); mpf_abs(tmf, tmf); if mpf_is_lt(tmf, em) and not mpf_is0(tmf) then ch := 80 else ch := length(string(mpf_decimal_alt(tmf, 55))); if (ch > 25) then begin application.MessageBox('a の値の小数点以下の値が長すぎます。','注意',0); goto EXT; end; end; if mpf_is0(b.im) then begin mpf_frac(b.re, tmf); mpf_abs(tmf, tmf); if mpf_is_lt(tmf, em) and not mpf_is0(tmf) then ch := 80 else ch := length(string(mpf_decimal_alt(tmf, 55))); if ch > 25 then begin application.MessageBox('b の値の小数点以下の値が長すぎます。','注意',0); goto EXT; end; end; if mpf_is0(c.im) then begin mpf_frac(c.re, tmf); mpf_abs(tmf, tmf); if mpf_is_lt(tmf, em) and not mpf_is0(tmf) then ch := 80 else ch := length(string(mpf_decimal_alt(tmf, 55))); if ch > 25 then begin application.MessageBox('c の値の小数点以下の値が長すぎます。','注意',0); goto EXT; end; end; f := 0; n := 0; // memo1.Clear; mpc_abs(z, absz); // |z| mpf_abs(z.re, az); XLE := false; mpc_set0(ans); if TN = 0 then begin // 通常計算 // z=0 Zがゼロの場合 a,b,cの値に関係なく 答えは 1 一番最初に確認 if mpc_is0(z) then begin memo1.Lines.Append('zの値がゼロです'); memo1.Lines.Append(' 1.0'); memo1.Lines.Append(' +0.0i'); goto EXT; end; // |Z| > 1 実数部0の時 if mpf_is_gt(absz, one) and mpf_is0(z.re) then begin goto ZG1; end; // 整数 (c <= 0 or a <= 0 or b <= 0) a,b,cの何れか又は全部が0を含み負の整数の場合 // zの値に関係なく通常の超幾何関数計算 Z<1の計算使用します。 二番目に確認 // /Z/の値が1より大きい場合aかb又はcがゼロになった時点で計算計算打ち切り // cが先か同時にゼロになった場合は±∞となります。 if zeroorounder(c) or (zeroorounder(a) or zeroorounder(b)) then begin memo1.Lines.Append(' (整数a<=0) or (整数b<=0) or (整数c<=0) '); Hypergeometric_function(a, b, c, z, eps, ans, n, f); goto TN0E; end; // z = 1 超幾何定理計算 複素数zの値が1の時の計算 // RE(c - a - b) > 0 の時は、超幾何定理計算 // RE(c - a - b) <= 0 の時は+∞か-∞になります // +か-かの判別は、zの値に0.7を与えて計算その時の値の符号で判定します。 if mpc_is1(z) then begin // z = 1 超幾何定理計算 Hypergeometric_function_zeq1(a, b, c, z, eps, ans, n, f); Memo1.Lines.Append(' z = 1 専用'); if f = 0 then begin Memo1.Lines.Append(' Re(c - a - b) > 0'); goto TN0E; end; // ∞符号設定 1から0.3 減算 0.7・・ 計算し∞±符号設定 if f = 8 then begin mpf_set_dbl(d1, 0.3); mpc_sub_mpf(z, d1, z); goto ZG2; end; end; // a,a+1,c or b+1,b,c /z/>1 時の近似計算設定 // aとbの差分が1の時の計算 mpf_add(a.re, one, ap.re); // 1加算 減算時桁落ち対策 mpf_add(b.re, one, bp.re); // 1加算 if mpf_is_gt(ap.re, bp.re) then begin // ap > bp なら ap <-> bp mpc_copy(ap, tmc); mpc_copy(bp, ap); mpc_copy(tmc, bp); end; mpf_sub(bp.re, ap.re, cp.re); // a,b 差分 差分は0~+ mpf_frac(a.re, tmf); // aの小数部 if checkbox4.Checked = true then begin mpf_read_decimal(cp.re, PAnsiChar(mpf_decimal(cp.re, 100) + #00)); // a,b 差分桁落ち対策 // a,b差分が1 虚数部が0 |z|>1 zの実数部が0かゼロ以上なら if mpf_is_eq(cp.re, one) and mpf_is0(ap.im) and mpf_is_gt(absz, one) and mpf_is_ge(z.re, zero) then begin if not mpf_is0(tmf) then begin // 小数部がゼロでなかったら 非整数なら if mpf_is_lt(absz, two) then begin // |z|が2より小さかったら 1 < |z| < 2 DS := 32; // 専用近似計算フラグセット 1-1/z c±Δ計算 goto ZG3; // pfaff 変換無し end else begin // |z|が2より大きかったら |z| >= 2 DS := 16; // 近似計算フラグセット 1/z a±Δ goto ZG2; // pfaff 変換不可 end; end else begin // a, b が整数なら if mpf_is_gt(absz, two) then begin // |z|が2より大きかったら /z/ > 2 DS := 16; // 近似計算 1/z a±Δ goto ZG1; // pfaff 変換可 end else begin // |z|が2より小さかったら 1 < |z| <= 2 DS := 32; // 専用近似計算フラグセット 1-1/z c±Δ計算 goto ZG3; // pfaff 変換無し end; end; end // else begin // a,b差分が1 虚数部が0 |z| >=0 Zの実数部が負数なら if mpf_is_eq(cp.re, one) and mpf_is0(ap.im) and mpf_is_ge(absz, one) and mpf_is_lt(z.re, zero) then begin DS := 8; // pfaff 変換フラグセット goto ZG1; // pfaff 変換 end; end; end; ZG3: // |a-b|=1 a,b 非整数 1-1/z 1 < |z| <= 2 c±Δ 近似計算 if (DS = 32) and not mpf_is0(z.re) then begin mpf_read_decimal(d1, PAnsiChar(ansistring('1E-40' + #00))); mpc_sub_mpf(c, d1, cp); Hypergeometric_function_of_first_kind_aeb(a, b, cp, z, eps, tmc, n, f); mpc_add_mpf(c, d1, cp); Hypergeometric_function_of_first_kind_aeb(a, b, cp, z, eps, ans, n, f); mpc_add(tmc, ans, tmc); mpc_div_mpf(tmc, two, ans); XLE := true; memo1.Lines.Append('|a-b|=1 a,b 1 < |z| <= 2'); memo1.Lines.Append('変換 1-1/z c ±Δ'); goto TN0E; end; // F a,a+1,c, z) or ( F b+1, b, c, z) z>1 の確認 幾何関数の計算はありません。 mpc_copy(a, ap); mpc_copy(b, bp); mpf_add(ap.re, one, ap.re); mpf_add(bp.re, one, bp.re); mpf_sub(bp.re, ap.re, cp.re); mpf_sub(ap.re, bp.re, am.re); mpf_read_decimal(cp.re, PAnsiChar(mpf_decimal(cp.re, 100) + #00)); // 桁落ち対策 mpf_read_decimal(am.re, PAnsiChar(mpf_decimal(am.re, 100) + #00)); // 桁落ち対策 if (mpf_is1(cp.re) or mpf_is1(am.re)) then begin if mpf_is_gt(absz, one) then begin if checkbox5.Checked = true then goto ZG1; // テスト用です 正しい答えでない場合があります memo1.Clear; memo1.Lines.Append('"a, a+1, c" or "b+1, b, c" にチェックを入れてください。'); memo1.Lines.Append('(F a,a+1, c, z) or ( F b+1, b, c, z) z > 1の条件では'); memo1.Lines.Append('演算出来ません。'); goto EXT; end; end; // F(1, 1, 2, z) z <> 1 の計算 専用 mpc_set1(tmc); // 1+0i mpc_sub(c, tmc, tmc); // c - (1+0i) if mpc_is1(a) and mpc_is1(b) and mpc_is1(tmc) and not mpc_is1(z) and not mpc_is0(z) then begin mpc_sub(tmc, z, tmc); mpc_ln(tmc, tmc); mpc_div(tmc, z, ans); mpc_chs(ans, ans); memo1.Lines.Append('F(1, 1, 2, z) z <> 1 の計算専用'); goto TN0E; end; // a = b, c / a,= 2 |z|>1 a b 非整数 // cが整数 c<=0 の場合は、先に処理されるので、aのみ近似計算 mpf_frac(a.re, ap.re); mpf_frac(b.re, bp.re); if not mpc_is0(a) and mpf_is_gt(z.re, zero) then mpc_div(c, a, cp); // c/a memo1.Lines.Append(ZeroErase(string('c/a ' + mpf_decimal(cp.re, 40)))); if mpf_is_gt(absz, one) then // z > 1 if (checkbox2.Checked = true) and not mpf_is0(ap.re) and not mpf_is0(bp.re) and mpf_is_eq(cp.re, two) and not mpc_is1(z) then begin // z範囲 1< z < 3 if mpf_is_lt(absz, three) then begin mpf_read_decimal(d1, PAnsiChar(ansistring('1E-60' + #00))); mpc_add_mpf(a, d1, ap); Hypergeometric_function_of_first_kind_aeb(ap, b, c, z, eps, tmc, n, f); mpc_sub_mpf(a, d1, am); Hypergeometric_function_of_first_kind_aeb(am, b, c, z, eps, ans, n, f); mpc_add(tmc, ans, ans); mpc_div_mpf(ans, two, ans); memo1.Lines.Append('a = b, c / a,= 2 |z|>1 a b 非整数'); memo1.Lines.Append('変換 1-1/z a ±Δ'); XLE := true; goto TN0E; end; end; // a = b, c <> a, |z| > 1 a,b z.im = 0 非整数 // Γ値に±∞無し if (checkbox2.Checked = true) and not mpf_is0(ap.re) and not mpf_is0(bp.re) and not mpf_is_eq(cp.re, two) then begin mpc_set1(tmc); // 1 mpc_add(a, b, ap); // a+b mpc_sub(ap, c, ap); // a+b-c mpc_add(ap, tmc, ap); // a+b-c+1 mpc_sub(c, a, am); // c-a mpc_sub(am, b, am); // c-a-b mpc_add(am, tmc, am); // c-a-b+1 if not zeroorounder(ap) and not zeroorounder(am) then if not zeroorounder(c) or not (zeroorounder(a) or not zeroorounder(b)) then begin mpc_sub(a, b, amb); mpc_sub(c, b, cmb); if mpc_is0(amb) and not mpc_is0(cmb) and mpf_is_gt(absz, one) and mpf_is_gt(z.re, zero) and mpf_is0(z.im) then begin Hypergeometric_function_of_first_kind_aeb(a, b, c, z, eps, ans, n, f); memo1.Lines.Append('a=b c<>a |z|>1'); memo1.Lines.Append('変換 1-1/z a ±Δ無し'); goto TN0E; end; end; end; ZG1: // Pfafの変換公式 a = b c / a = 2 c / b = 2 は計算出来ない // zの実数部がゼロの時で/z/=1ならPfafの変換使用 // |z|>=1 で a,b,cの虚数部が0でない場合はpfaff使用不可 mpf_frac(a.re, ap.re); mpf_frac(b.re, bp.re); mpf_frac(c.re, cp.re); if (mpf_is_gt(absz, dnine) and mpf_is_le(absz, one)) or ((mpf_is_gt(absz, one) and (mpf_is_lt(absz, two) and mpf_is0(ap.re) and mpf_is0(bp.re) and mpf_is0(cp.re) and (mpf_is0(a.im) and mpf_is0(b.im) and mpf_is0(c.im))))) then begin if mpf_is0(z.re) then mpf_abs(z.im, tmf); // |zim| if (checkbox3.Checked = true) or mpf_is1(tmf) then begin if not mpc_is0(a) then mpc_div(c, a, ap); if not mpc_is0(b) then mpc_div(c, b, bp); if mpf_is_eq(ap.re, two) and mpf_is_eq(bp.re, two) and mpf_is0(z.im) then else begin mpc_sub(a, b, am); mpc_sub(c, b, cp); // |z| < dnine {z| < 2 z<>1 なら Pfafの変換 if mpf_is_gt(absz, dnine) and mpf_is_lt(absz, two) and not mpc_is1(z) then begin if not (mpc_is0(am) and not (mpc_is0(am) and (mpf_is_lt(cp.re, one) or mpf_is_gt(cp.re, one)))) then begin mpc_copy(z, zbackP); DS := DS or 4; // 変換フラグセット mpc_set1(tmc); mpc_sub(z, tmc, tmc); // z - 1 mpc_div(z, tmc, z); // z = z/(z-1); mpc_abs(z, absz); // |z| mpc_sub(c, b, b); // b = c - b end; // a=b c=a+1 c=b+1 の時変換後にaにΔ値加減算 if (mpc_is0(am) and not (mpf_is_lt(cp.re, one) or mpf_is_gt(cp.re, one))) then begin mpc_copy(z, zbackP); DS := DS or 4 or 128; // 変換フラグセット mpc_set1(tmc); mpc_sub(z, tmc, tmc); // z - 1 mpc_div(z, tmc, z); // z = z/(z-1); mpc_abs(z, absz); // |z| mpc_sub(c, b, b); // b = c - b XLE := true; end; end; end; end; end else begin if mpf_is_lt(absz, two) and (mpf_is_gt(absz, one)) then begin Hypergeometric_function_of_first_kind_aeb(a, b, c, z, eps, ans, n, f); memo1.Lines.Append('1-1/z 1<|z|<2 Δ無し)'); goto TN0E; end; end; ZG2: // z > 1 // Γ値の値が±∞になる場合、微笑値Δを加減算して計算平均値を答えにしています。 // a=bの計算の時は、aのみ微笑値Δを加減算 a=bとa<>bでは、平均値の計算が違います。 if mpf_is_gt(absz, one) then begin // |z|が1より大きかったら if DS = 0 then XLE := false; mpc_sub(a, b, amb); mpc_sub(b, a, bma); mpc_sub(c, a, cma); mpc_sub(c, b, cmb); mpc_sub(a, b, aeb); // X > 1 計算で Γ値が+∞-∞になるなら近似計算 Δα値を加算減算して計算し平均値を求めます if checkbox1.Checked = true then begin if mpc_is0(amb) then mpf_read_decimal(d1, PAnsiChar(ansistring('1E-19' + #00))) else mpf_read_decimal(d1, PAnsiChar(ansistring('1E-45' + #00))); if DS and 128 = 128 then mpf_read_decimal(d1, PAnsiChar(ansistring('1.8E-29' + #00))); df := 0; // a=b a, b, if mpc_is0(amb) or (DS and 16 = 16) or (DS and 128 = 128) then begin // a=b の場合 又は DS=16 (a, b=a+1, b+1 b) df := df or 16; // aのみΔ加算減算計算 mpc_set1(aeb); // df=16時はa±Δで計算する為 aeb では無くなります end; mpc_copy(a, ap); if df and 16 = 16 then else begin if zeroorounder(amb) then df := df or 1; // x <= 0 で 整数 なら XLE = true if zeroorounder(bma) then df := df or 2; if zeroorounder(cma) then df := df or 4; if zeroorounder(cmb) then df := df or 8; end; if (df = 13) or (df = 14) then begin df := 16; mpc_set1(aeb); end; if df <> 0 then begin XLE := true; if df and 16 = 16 then begin mpc_add_mpf(a, d1, ap); mpc_sub(ap, b, amb); mpc_sub(b, ap, bma); mpc_sub(c, ap, cma); mpc_sub(c, b, cmb); end; if df and 1 = 1 then mpc_add_mpf(amb, d1, amb); if df and 2 = 2 then mpc_add_mpf(bma, d1, bma); if df and 4 = 4 then mpc_add_mpf(cma, d1, cma); if df and 8 = 8 then mpc_add_mpf(cmb, d1, cmb); Hypergeometric_function_of_first_kind(ap, b, c, amb, bma, cma, cmb, aeb, z, eps, tmc, n, f); // Δ加算計算 memo1.Lines.Append(ZeroErase(string('tmc ' + mpf_decimal(tmc.re, 40)))); mpc_sub(a, b, amb); mpc_sub(b, a, bma); mpc_sub(c, a, cma); mpc_sub(c, b, cmb); mpc_copy(a, am); if df and 16 = 16 then begin mpc_sub_mpf(a, d1, am); mpc_sub(am, b, amb); mpc_sub(b, am, bma); mpc_sub(c, am, cma); mpc_sub(c, b, cmb); end; if df and 1 = 1 then mpc_sub_mpf(amb, d1, amb); if df and 2 = 2 then mpc_sub_mpf(bma, d1, bma); if df and 4 = 4 then mpc_sub_mpf(cma, d1, cma); if df and 8 = 8 then mpc_sub_mpf(cmb, d1, cmb); Hypergeometric_function_of_first_kind(am, b, c, amb, bma, cma, cmb, aeb, z, eps, ans, n, f); // Δ減算計算 memo1.Lines.Append(ZeroErase(string('ans ' + mpf_decimal(ans.re, 42)))); mpc_add(ans, tmc, ans); mpc_div_mpf(ans, two, ans); // 平均値 if df = 16 then memo1.Lines.Append(' 1/z a ±Δ 計算') else memo1.Lines.Append(' 1/z ±Δ 計算'); end else begin Hypergeometric_function_of_first_kind(a, b, c, amb, bma, cma, cmb, aeb, z, eps, ans, n, f); // Δ=0 memo1.Lines.Append(' 1/z Δ=0 計算'); end; end else begin // 無限大回避のチェックを外すと使用されます Hypergeometric_function_of_first_kind(a, b, c, amb, bma, cma, cmb, aeb, z, eps, ans, n, f); // Δ無し Memo1.Lines.Append('1/z ±Δ無し'); end; end else if not mpc_is1(z) then begin // z < 1 通常の超幾何関数計算 Hypergeometric_function(a, b, c, z, eps, ans, n, f); Memo1.Lines.Append(' z < 1 ±Δ無し'); end; end; // TN=0 end TN0E: if TN = 1 then begin // arctan計算 mpc_mul(z, z, mz2); mpc_chs(mz2, mz2); if mpf_is_gt(absz, one) then begin // zが1より大きかったら mpc_sub(a, b, amb); mpc_sub(b, a, bma); mpc_sub(c, a, cma); mpc_sub(c, b, cmb); Hypergeometric_function_of_first_kind(a, b, c, amb, bma, cma, cmb, amb, mz2, eps, ans, n, f); end else // zが1より小さかったら Hypergeometric_function(a, b, c, mz2, eps, ans, n, f); end; if TN = 2 then begin // arcsin計算 if not mpf_is1(az) then begin mpc_mul(z, z, mz2); Hypergeometric_function(a, b, c, mz2, eps, ans, n, f); end; end; if BR then memo1.Lines.Append('計算が途中で打ち切られました、計算結果は正しくありません。'); if n >= NC then begin memo1.Lines.Append('計算が' + intTostr(NC) + 'Loopで収束しませんでした。'); memo1.Lines.Append('計算結果は正しくありません。'); end else begin if TN = 0 then begin // 通常計算 memo1.Lines.Append('ガウスの超幾何関数'); if XLE and checkbox1.Checked then memo1.Lines.Append(' 近似計算'); // memo1.Lines.Append('計算Loop数' + inttostr(n)); end; end; if (f = 1) or (f = 2) then begin // if mpf_is0(ans.re) then memo1.Lines.Append('0'); if mpf_is_ge(ans.re, zero) then memo1.Lines.Append('∞') else memo1.Lines.Append('-∞'); if mpf_is_gt(ans.im, zero) then memo1.Lines.Append('+∞i'); if mpf_is_lt(ans.im, zero) then memo1.Lines.Append('-∞i'); end; if TN = 0 then begin // 通常計算 // 絶対値が指定値より小さかったら0セット zerounde1em100(ans); // z=1 計算 ∞時 出力 if f = 8 then begin memo1.Lines.Append('z = 1'); memo1.Lines.Append(' Re(c - a - b) <= 0'); if mpf_is_ge(ans.re, zero) then memo1.Lines.Append(' ∞') else memo1.Lines.Append('-∞'); if mpf_is_gt(ans.im, zero) then memo1.Lines.Append('+∞i'); if mpf_is_lt(ans.im, zero) then memo1.Lines.Append('-∞i'); goto EXT; end; // pfaff変換時出力 if DS and 4 = 4 then begin mpc_set1(tmc); // 1 mpc_sub(tmc, zbackp, tmc); // 1-z mpc_chs(a, ap); // -a mpc_powa(tmc, ap, tmc); // (1-z)^-a mpc_mul(ans, tmc, ans); // ans = ans * ((1-z)^-a) memo1.Lines.Append(' Pfaff'); zerounde1em100(ans); end; // 二次 z^2/(z^2/(z4-4)) 変換時出力 必ずpfaffの後に実行 if (DS and 8 = 8) or (DS = 64) then begin mpc_set1(tmc); // 1 mpc_sub(tmc, zback, tmc); // 1-z mpc_chs(aback, aback); // -a mpc_div_mpf(aback, two, aback); // -a/2 mpc_powa(tmc, aback, tmc); // (1-z)^-a/2 mpc_mul(ans, tmc, ans); // ans = ans * ((1-z)^-a/2) memo1.Lines.Append(' F(c=2a or c=2b, z^2/(z4-4)'); zerounde1em100(ans); end; // 計算結果表示 近似計算時は40桁 通常は50桁表示 if f = 16 then begin memo1.Lines.Append('演算出来ません。'); end; if (f = 0) or (f = 4) then begin mpf_abs(ans.re, az); if mpf_is_gt(az, infs) then begin if mpf_is_gt(ans.re, zero) then memo1.Lines.Append(' ∞') else memo1.Lines.Append(' -∞'); end else if XLE and checkbox1.Checked then begin mpf_abs(ans.re, tmf); if mpf_is_lt(tmf, em40) then mpf_set0(ans.re); memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(ans.re, 35)))); end else memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(ans.re, 50)))); mpf_abs(ans.im, az); if mpf_is_gt(az, infs) then begin if mpf_is_gt(ans.im, zero) then memo1.Lines.Append(' +∞i') else memo1.Lines.Append(' -∞i'); end else begin mpf_abs(ans.re, az); if mpf_is_lt(az, infs) then if XLE and checkbox1.Checked then begin mpf_abs(ans.im, tmf); if mpf_is_lt(tmf, em40) then mpf_set0(ans.im); memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(ans.im, 35))) + ' i'); end else memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(ans.im, 50))) + ' i'); end; end; end; if TN = 1 then begin // arctan計算 mpc_mul(ans, z, tans); // z * if DS = 1 then memo1.Lines.Append('arctan(z) rad 超幾何関数計算'); if DS = 2 then memo1.Lines.Append('arcsin(z) rad 超幾何関数計算'); memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(tans.re, 50)))); mpc_arctan(z, dat); memo1.Lines.Append('rad 組込み関数計算'); memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(dat.re, 50)))); end; if TN = 2 then begin // arcsin計算 if not mpf_is1(az) then mpc_mul(ans, z, tans) // z * else begin mpf_set_pi(tans.re); mpf_div(tans.re, two, tans.re); mpc_mul(tans, z, tans) // z * end; if DS = 1 then memo1.Lines.Append('arctan(z) rad 超幾何関数計算'); if DS = 2 then memo1.Lines.Append('arcsin(z) rad 超幾何関数計算'); memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(tans.re, 50)))); mpc_arcsin(z, dat); memo1.Lines.Append('rad 組込み関数計算'); memo1.Lines.Append(ZeroErase(string(' ' + mpf_decimal(dat.re, 50)))); end; EXT: button1.Enabled := True; TN := 0; // artn arsin 解除 DS := 0; // artn arsin 解除 mpc_clear5(a, b, c, z, ans); mpf_clear5(eps, az, tmf, em40, em); mpc_clear4(mz2, tans, dat, tmc); mpc_clear5(amb, bma, cma, cmb, aeb); mpf_clear3(d1, d2, dnine); mpc_clear4(ap, bp, cp, zbackp); mpc_clear5(am, bm, cm, zback, aback); mpf_clear(absz); end; // 初期設定 procedure TForm1.FormCreate(Sender: TObject); var i : integer; N, D, tmp : mp_float; ctmp : mp_complex; begin mpf_set_default_prec(1000); precisionedit.Text := intTostr(mpf_get_default_prec); memo1.Clear; Label1.Caption := ' 設定値によって、中々収束しません。' + #13#10 + 'その時は計算打切りボタンで停止して' + #13#10 + '下さい。'; BR := false; TN := 0; // 計算実行 0 通常 1 artan 2 arsin DS := 0; // 計算表示 0 通常 1 artan 2 arsin setlength(BM, NB + 1); // Γ関数用ベルヌーイ数配列 for i := 0 to NB do mpf_init(BM[i]); mpf_init3(N, D, tmp); mpf_init5(zero, one, two, four, three); mpf_init3(pai, maxmpf, infs); mpc_init(log_2pis2); mpc_init(ctmp); // 0,1,2,3,4, π mpf_set0(zero); mpf_set1(one); mpf_set_int(two, 2); mpf_set_int(three, 3); mpf_set_int(four, 4); mpf_set_pi(pai); // ∞設定値値 mpf_read_decimal(maxmpf, PAnsiChar(ansistring('1.0e+100000000' + #00))); // ∞判別値 mpf_read_decimal(infs, PAnsiChar(ansistring('1.0e+1000000' + #00))); // ln(2π)/2 複素数 mpc_set0(ctmp); // 0 + 0i mpf_mul(pai, two, ctmp.re); // 2π+0i mpc_ln(ctmp, ctmp); // ln(2π+0i) mpc_div_mpf(ctmp, two, log_2pis2); // ln(2π+0i)/2 // ベルヌーイ数分母分子配列表作成 Bernoulli_number_BigInteger; // 分母と分子に分かれているΓ関数用ベルヌーイ数を浮動小数点の値に変換します。 // 分母の値がΓ関数用に変換されています。 for i := 0 to NB do begin mpf_read_decimal(N, PAnsiChar(ansistring(NumeratorString[i] + #00))); mpf_read_decimal(D, PAnsiChar(ansistring(DenominatorString[i] + #00))); mpf_div(N, D, BM[i]); // BM[] Γ関数用ベルヌーイ数配列 end; comment; mpf_clear3(N, D, tmp); mpc_clear(ctmp); end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); var i : integer; begin for i := 0 to NB do mpf_clear(BM[i]); mpf_clear5(zero, one, two, four, three); mpf_clear3(pai, maxmpf, infs); mpc_clear(log_2pis2); end; procedure TForm1.Button2Click(Sender: TObject); begin comment; end; end.
Hypergeometric_function.zip
三角関数、逆三角関数、その他関数 に戻る