逆誤差関数、誤差関数
逆誤差関数には、前述の逆誤差関数があるのですが、有効桁数を50桁程度で、1に近い値となると、ckの大きな配列の値を必要とするので、あまり実用的ではありません。
18桁程度の精度のものは、インターネットで公開されているプログラムをDelphiに変換してみました。
Extendedで17桁、Doubleの演算では15桁程度の精度が得られます。 逆誤差関数2 逆誤差関数3
精度のが高い逆誤差関数の必要性はあまりないと思われますが、計算できないのも問題なので、演算に時間が掛かるのですが、誤差関数erf(z)を利用して逆誤差関数erfinv(y)を求めるプログラムを作成てみました。
erf(z)の計算時、z<2.4はテーラー展開z>=2.4は連分数の計算をしています。
プログラムはerf(z)のzの最大値は100、erfinv(y)の値は0.999・・9の9の連続値が最大4345個となっています。
erf(z)のzの値は、プログラムを修正すれば、もっと大きな値を与えることができます。
逆誤差関数erfinv(y)のyの値を9の個数+αで与える場合は、負数を与えることは出来ません。
yの値と、erfinv(y)の符号は同じになるので、問題ないでしょう。
'9'の個数で、yの値を与える場合、9に続く値の与え方として
0.0012345、1.2345e-3の様な場合は加算、345234の様に少数点がない場合9の後に続く値として0.9999345234の様に取り扱いされます。
'9'の数を0とすれば、通常の符号付き入力として取り扱われます。
erf(z)のzの値が大きくなると、erfinv(y)の計算時間は、非常に長くなります。
zの値が100になるような場合は、cpuの能力によりますが、遅いので数分、速いので数十秒必要とします。
y=0.99・・9の9値が50個程度のerfinv(y)の計算なら十数秒で計算出来るので問題ないでしょう。
逆誤差関数の計算方法は、単純な計算方法で、y=erf(z)のz=0の時yの値もゼロとなり、正比例することを利用します。
目標として当たられるのはyの値なので単純な近似計算を行います。
epsilonの値は、yの絶対値が0.1以下なら1e-200、0.1以上なら1e-80を与えます。
演算結果として50桁を得るためには、yの値が0.1以上なら1E-80で十分です。
0.1以下の場合、zの値が小さくなるので、epsilonの値を小さくする必要があります。
yの値に応じてepsilonの値を計算してあげた方が、計算時間を節約できます。
その時には、除算時の有効桁数も一緒に変更した方が良いでしょう。
プログラム
Biginteger & Bigdecimal の組み込み方は第1種ケルビン関数を参照して下さい。
main.pas
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, system.UITypes, Vcl.Buttons; type TForm1 = class(TForm) zEdit: TLabeledEdit; calcBtn: TButton; ansREdit: TLabeledEdit; nEdit: TEdit; OneMansEdit: TLabeledEdit; Label1: TLabel; Memo1: TMemo; yEdit: TLabeledEdit; invBtn: TBitBtn; CheckBox1: TCheckBox; n9Edit: TLabeledEdit; p9aedit: TLabeledEdit; inv9Btn: TButton; Label2: TLabel; procedure calcBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure invBtnClick(Sender: TObject); procedure inv9BtnClick(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses System.Character, Sub_big, Velthuis.BigIntegers, Velthuis.Bigdecimals; const ZINMAX = '100'; // |z|の入力最大値 有効桁数と収束判定値の関係での値 EPSC = '1e-500'; // 誤差関数収束反対値 // 除算有効桁数が不足し、収束判定値が大きいと演算結果が // 1.0を超えます。 //------------------------------------------------------------------------------ // 演算時間 秒 // n8 9の数 function inversetime(n9: integer): double; const r = 0.911927968427609; a = -5; b = 8; begin if n9 = 0 then result := 1 else result := b * ln(n9 + 1) + a; result := round(result); end; //------------------------------------------------------------------------------ // 数値の後ろのゼロ消去 function ZeroErase(s : string): string; const EP = 'e'; ZC = '0'; dt = '.'; var c : char; i, j, k, l : integer; begin l := length(s); // l文字長さ j := 1; // j=1初期化 for i := 1 to l do begin // 一文字目から c := s[i]; // 一文字取り出し if c = EP then begin // 'e'だったら j := i - 1; // eの前の文字No break; // ブレーク end; j := i; // 'e'がなかったらj=i end; result := ''; // ''設定 if j < l then begin // jが文字長さより小さかったら for i := l downto j + 1 do // 文字の後ろから result := s[i] + result; // 'e'迄コピー end; K := 1; // k=1初期化 for i := j downto 1 do begin // 'e'の前の文字から c := s[i]; // 一文字取り出し'0'は読み飛ばす if c <> ZC then begin // '0'で無かったら k := i; // k=i if c = DT then k := k + 1; // '.'だったら k=i+1 '.'の後の'0'は残す break; // ブレーク end; end; for i := k downto 1 do // kから1文字目までコピー result := s[i] + result; // 前に追加コピー end; //---------------------------------- 誤差関数 ---------------------------------- // erf(z) 誤差関数 // z < 2.4 テーラー展開計算 // z >= 2.4 連分数計算 function Error_function(z : bigdecimal): bigdecimal; const IMAX = 350; // 連分数計算 Loop数 var mzh2, zhn, s, tmp, y, a : bigdecimal; epsilon, sabs : bigdecimal; one, two, nl, nn : bigdecimal; n : biginteger; ione : biginteger; dpcs, i : integer; begin dpcs := bigdecimal.DefaultPrecision; // 除算有効桁数 one := bigdecimal.One; // 1 ione := biginteger.One; epsilon := EPSC; // 収束判定値 if z.Abs(z) < '2.4' then begin // テーラー展開 mzh2 := -z * z; // -z^2 s := z; // n = 0時 z nl := one; // 0! = 1 zhn := z; // n = 0時 z n := ione; // n=1から repeat nn := n + n + one; // 2n+1 nn := nn * nl; // n!(2n+1) zhn := zhn * mzh2; // ((-1)^n)(z^(2n+1)) nn := nn.RoundToPrecision(dpcs); // 除算前桁合わせ zhn := zhn.RoundToPrecision(dpcs); // 除算前桁合わせ tmp := zhn / nn; // ((-1)^n)(z^(2n+1))/(n!(2n+1)) s := s + tmp; // Σ+Δ n := n + ione; // inc(n) nl := nl * n; // n! sabs := tmp.Abs(tmp); // |Δ| until sabs < epsilon; result := s * pai2; // Σ* 2/√(π) form1.nedit.Text := 'loops= ' + n.ToString; exit; end; two := bigdecimal.two; // 連分数計算 y := z.Abs(z) * two; // 2z n := IMAX; a := bigdecimal.Zero; // a = 0 for i := IMAX downto 1 do begin a := n * (two / (y + a)); n := n - ione; end; a := 1 - exp_big(-z * z) / (y + a) * two / pib.Sqrt(pib); if z < '0' then result := -a else result := a; form1.nedit.Text := '連分数 loops= ' + inttostr(IMAX); end; //------------------------------------------------------------------------------ // 答0.99・9xxxの9の値を数えると同時に元の値から0.99・9xxx-0.99・9で0.00・xxxを得ます。 // 戻り値'9'の数 function nineNo(x : bigdecimal; var ans: bigdecimal): integer; const NINE = '9'; var char9 : char; i, lng, count : integer; str, ninestr : string; s9f : boolean; nines : bigdecimal; begin s9f := false; // '9'フラグリセット char9 := NINE; // '9' str := x.ToPlainString; // x -> string lng := length(str); // 文字長さ ninestr := '0.'; // '0.' count := 0; // '9'の数リセット for i := 1 to lng do begin // 1文字目から if str[i] = char9 then begin // '9'なら if i = 3 then s9f := true; // 3文字目が'9'だったら'9'フラグセット if s9f then begin // '9'フラグtrueなら inc(count); // '9'の数インクリメント ninestr := ninestr + char9; // '0.xx' + '9' end; end else s9f := false; // '9'でなかったら'9'フラグリセット end; if count > 0 then begin // '9'の数が0以上なら nines := ninestr; // '0.9・・9' -> 数値変換 ans := x - nines; // ans = 0.9・・9xxxxx - 0.9・・9 = 0.0・・0xxxxx end else ans := x; // ans = x 変化なし この時 '9'の数=0 result := count; // '9'の数 end; //------------------------------------------------------------------------------ // error function calc // zの値が∞だとerror関数の値が1になるのですが、演算桁数の関係で // 50桁表示でzの値が10.7程度で1になってしまうため9の数での表現を採用しています。 Procedure calc_error_function; var z, absz, ans, mans, ansm99, zmax, one, ansmone : bigdecimal; nineN : integer; str99 : string; begin zmax := ZINMAX; try z := form1.zEdit.Text; except on EConverterror do begin MessageDlg('z の値に間違いがあります。', mtError, [mbOK], 0); exit; end; end; absz := z.Abs(z); if absz > zmax then begin MessageDlg('z の絶対値が演算の最大値より大きくなっています。', mtError, [mbOK], 0); exit; end; one := bigdecimal.One; // error 関数計算 ans := Error_function(z); // errorC 関数計算 mans := bigdecimal.One - ans; // zの値が1.2を超えると0.999・・9の9の値が増えるの9の値を数で表現 0. + 9の数+0.99・9を減算した値として表示 if z >= 0 then nineN := nineNo(ans, ansm99) else nineN := nineNo(-ans, ansm99); // 0.'9'・・・の'9'は有効桁数とならない様なので変更 ansm99 := ansm99.RoundToPrecision(50); if ans = '0' then form1.ansREdit.Text := ' 0.0' else begin if (nineN > 0) and (Form1.CheckBox1.Checked = false) then begin if ansm99 = bigdecimal.Zero then str99 := '0' else str99 := ansm99.ToString; if z >= 0 then Form1.ansREdit.Text := ' 0. 9xx' + inttostr(nineN) + '個 + ' + str99 else Form1.ansREdit.Text := '-0. 9xx' + inttostr(nineN) + '個 - ' + str99; end else begin ans := ans.RoundToPrecision(50); Form1.ansREdit.Text := ZeroErase(' ' + ans.ToString); end; end; if mans > one then ansmone := mans - one else ansmone := mans; nineN := nineNo(ansmone, ansm99); ansm99 := ansm99.RoundToPrecision(50); if (nineN > 0) and (Form1.CheckBox1.Checked = false) then begin if ansm99 = bigdecimal.Zero then str99 := '0' else str99 := ansm99.ToString; if mans > one then Form1.OneMansEdit.Text := ' 1. 9xx' + inttostr(nineN) + '個 + ' + str99 else Form1.OneMansEdit.Text := ' 0. 9xx' + inttostr(nineN) + '個 + ' + str99; end else begin mans := mans.RoundToPrecision(50); form1.OneMansEdit.Text := ' ' + ZeroErase(mans.ToString); end; end; //----------------------------- 誤差関数計算 ----------------------------------- // erf(z) procedure TForm1.calcBtnClick(Sender: TObject); begin calcBtn.Enabled:= false; bigdecimal.DefaultPrecision := DPS; calc_error_function; calcBtn.Enabled:= true; end; //----------------------------- 逆誤差関数 ------------------------------------- // erfの計算からerfinvの値を逆算します // erf(1)から始めてerf(x)の値をyに近づけます function erfinv_function(y : bigdecimal; var n : integer): bigdecimal; const MINX1 = '1e-200'; // MINX2 = '1e-100'; // DPS = 1000 MINX2 = '1e-80'; // DPS = 600 var ans, dx, mx, absy, ty, quarter : bigdecimal; begin if y = '0' then begin result := '0'; exit; end; absy := y.Abs(y); mx := MINX2; if absy < '0.1' then mx := MINX1; // 値による収束判定値変更 quarter := bigdecimal.One / bigdecimal.Two; quarter := quarter / bigdecimal.Two; // 0.25 dx := bigdecimal.Two; // 2 ty := dx; n := 0; repeat ans := Error_function(ty); // 誤差関数 if ans > absy then begin ty := ty - dx; dx := dx * quarter; // dx * 0.25 ty := ty + dx; end else ty := ty + dx; inc(n); until (dx < mx) or (ans = absy); if y < '0' then ty := -ty; result := ty; end; // 逆誤差関数の計算 procedure inverse_error_function(y : bigdecimal); var ans, absy, one, dlt : bigdecimal; n : integer; begin if (y > '1') or (y < '-1') then begin application.MessageBox('yの値が範囲外です。','注意', 0); exit; end; absy := y.Abs(y); if absy < '1' then begin one := '1'; dlt := '1e-4346'; dlt := one - dlt; if absy > dlt then begin // 0.9999999 9 9 が4345個迄 application.MessageBox('yの値が1に近すぎます。(0.9999・・・・9)','注意', 0); exit; end; end; if (y <> '0') and (absy < '1e-100') then begin application.MessageBox('yの絶対値が小さすぎます。','注意', 0); exit; end; if y = '1' then begin Form1.memo1.Lines.Append('erfinv(1) = INFINITY'); exit; end; if y = '-1' then begin Form1.memo1.Lines.Append('erfinv(-1) = -INFINITY'); exit; end; Form1.Memo1.Lines.Append('暫く時間が掛かります。'); application.ProcessMessages; ans := erfinv_function(y, n); // 逆誤差関数 ans := ans.RoundToPrecision(50); form1.Memo1.Clear; Form1.memo1.Lines.Append('入力値 y = ' + y.ToPlainString); Form1.memo1.Lines.Append('erfinv'); Form1.Memo1.Lines.Append('Loops = ' + intTostr(n)); if ans = '0' then Form1.memo1.Lines.Append('erfinv(y) = 0.0') else Form1.memo1.Lines.Append('erfinv(y) = ' + ZeroErase(ans.ToString)); end; // 逆誤差関数計算 y値入力 procedure TForm1.invBtnClick(Sender: TObject); var y : bigdecimal; begin try y := form1.yEdit.Text; except on EConverterror do begin MessageDlg('y の値に間違いがあります。', mtError, [mbOK], 0); exit; end; end; invBtn.Enabled := false; memo1.Clear; inverse_error_function(y); // 逆誤差関数 invBtn.Enabled := true; end; //------------------------------------------------------------------------------ // 0 そのまま文字9の後に文字として追加 // 1 0.99・・の値に x.xxe^-yとして加算 // 3 入力エラー function p9aCondition(s : string; n9: integer): integer; const dc = '.'; me = 'e'; le = 'E'; mc = '-'; var i, l : integer; s9 : string; b9, pa : bigdecimal; cc : char; EF : boolean; begin l := length(s); //文字の長さ EF := false; for i := l downto 1 do begin cc := s[i]; if cc = me then EF := True; if cc = le then EF := True; if cc = dc then EF := True; end; if EF then begin s9 := '1.0e-' + intTostr(n9); b9 := s9; pa := s; if pa > s9 then begin MessageDlg(' +α の値が大きすぎます。', mtWarning, [mbOK], 0); result := 3; exit; end; result := 1; exit; end; result := 0; end; // 逆誤差関数計算 // 9の数入力モード procedure TForm1.inv9BtnClick(Sender: TObject); const YMAX = 4345; var n9, ch, j : integer; b9, pa, yb : bigdecimal; ystr : string; begin val(n9edit.Text, n9, ch); if ch <> 0 then begin MessageDlg(' 9 のn数に間違いがあります。', mterror, [mbOK], 0); exit; end; if n9 > YMAX then begin MessageDlg(' 9 のn数は'+ intTostr(YMAX) + '迄です。', mtWarning, [mbOK], 0); exit; end; try pa := p9aEdit.Text; except on EConverterror do begin MessageDlg('+α の値に間違いがあります。', mtError, [mbOK], 0); exit; end; end; ch := p9aCondition(p9aEdit.Text, n9); if ch = 3 then exit; // 入力エラーなら終了 if ch = 0 then begin // テキスト加算 ystr := '0.'; for j := 1 to n9 do ystr := ystr + '9'; ystr := ystr + p9aEdit.Text; try yb := ystr; except on EConverterror do begin MessageDlg('+α の値に間違いがあります。', mtError, [mbOK], 0); exit; end; end; end; if ch = 1 then begin // 数値加算 ystr := '0.'; for j := 1 to n9 do ystr := ystr + '9'; b9 := ystr; yb := b9 + pa; end; memo1.Clear; memo1.Lines.Append('入力値 y = ' + yb.ToPlainString); memo1.Lines.Append('約 ' + floattostr(inversetime(n9)) + '秒位'); inv9Btn.Enabled := false; inverse_error_function(yb); // 逆誤差関数 inv9Btn.Enabled := true; end; //------------------------------------------------------------------------------ // 初期値 procedure TForm1.FormCreate(Sender: TObject); var two : bigdecimal; begin bigdecimal.DefaultPrecision := DPS; // 除算有効桁数設定 zedit.EditLabel.Caption := '|z|<=' + ZINMAX; label1.Caption := 'Zの値が無限大の時erf(∞)=1となるのですが演算上入力の最大値は' + ZINMAX + 'です。'; nEdit.Text := 'loops ='; pib := pi_big; // π 600桁 two := bigdecimal.Two; // 2 pai2 := two / pib.Sqrt(pib, DPS + DPS); // 2/√(π) end; end.
Sub_big.pas
unit Sub_big; interface uses Vcl.Forms, Velthuis.BigIntegers, Velthuis.Bigdecimals; const DPS = 600; // 除算有効桁数 // 有効桁数が不足、収束判定値が大きいと演算結果が // 1.0を超えます。 var pib, pai2 : bigdecimal; // π bigdecimal function exp_big(x: bigdecimal): bigdecimal; // e~x function pi_big: Bigdecimal; // π implementation // exp(x) e^x 冪級数 テイラー級数 // exp(x) = 1 + x + x^2/2! + x^3/3! + x^4/4! .... function exp_big(x: bigdecimal): bigdecimal; var dpcs : integer; a, e, prev, zero, one, two, d : bigdecimal; i, ione: bigInteger; begin dpcs := BigDecimal.DefaultPrecision; zero := '0'; one := '1'; two := '2'; e := x; // exp(t)計算開始 e=x if x < zero then e := -x; // x が負数だったらe 正数に d := e; // d 初期値 e = /x/ a := d; // a 初期値 d = e = /x/ i := '2'; ione := '1'; repeat prev := e; // 判定値保存 a := a * (d / i); // a = (d^i)/(i!) a := a.RoundToPrecision(dpcs); e := e + a; // e = e + (d^i)/(i!) e := e.RoundToPrecision(dpcs); i := i + ione; // inc(i) until e = prev; // 桁落ちにより値が変わらなくなったら終了 e := e + one; // e = 1 + d + d^2/2! + d^3/3! ~ e := e.RoundToPrecision(dpcs); one := one.RoundToPrecision(dpcs); if x < '0' then e := one / e; // xが負数だったら答えは逆数 result := e; end; //--------------------------------- Ln(x)--------------------------------------- // x = m * 2^n のnの値と2^nの値を戻します // result = n // ta = 2^n // m = x / 2^n function frexpa(x: bigdecimal; var ta: biginteger): integer; var tb: biginteger; xi, one: bigdecimal; n, j, s, pcs : integer; begin pcs := BigDecimal.DefaultPrecision; one := '1'; one := one.RoundToPrecision(pcs); xi := x; // x保存 if xi < one then x := one / x; // 1より小さかったら逆数 ta := '1'; n := 0; j := 0; // シフト回数クリア ta := '1'; // ta初期値 s := 4096; // s=4^i i = 6 repeat while x > ta do begin biginteger.ShiftLeft(ta, s, tb); // s分左シフト ta := tb; inc(j); // シフト回数インクリメント end; if (s > 1) and (j > 0) then begin // ta > x になったら dec(j); // シフト回数デクリメント biginteger.Shiftright(ta, s, tb); // s分右シフト ta := tb; end; n := n + s * j; // 2^nのn計算 j := 0; // シフト回数クリア s := s shr 2; // sの値を1/4にする 右へ2ビットシフト // s := s div 4; // sの値を1/4にする until s = 0; // s= ...16, 4, 1, 0 if xi < one then begin // より小さかったら n := -n + 1; // 2^nのn値負数 biginteger.Shiftright(ta, 1, tb); // 上式+1により右シフト ta := tb; end; result := n // ta = 2^n end; // 小さい値のlog計算 // xi 実数 // dpcs 有効桁数 // ans log値 // 戻り値 Loopオーバーフロー 無し true 有り false // loop制限の無い場合 1e-4~1e4 が計算出来る範囲 // loop制限 5.8e-3 ~1.73e2 (kk=10000の場合) function Log_11(x: bigdecimal; dpcs: integer; var ans: bigdecimal): boolean; const KK = 10000; var one, two, x1, x2, i, s, last: bigdecimal; k : integer; begin result := true; one := '1'; two := '2'; x1 := (x - one) / (x + one); // x1 = (x-1)/(x+1) x2 := x1 * x1; // x1^2 x2 := x2.RoundToPrecision(dpcs); i := one; // i=1 s := x1; // s初期値 k := 0; // 長ループ脱出用カウンタ0 repeat x1 := x1 * x2; // x1^2n+1 x1 := x1.RoundToPrecision(dpcs); i := i + two; // 2n+1 i := i.RoundToPrecision(dpcs); last := s; // 判定用sの値保存 s := s + x1 / i; // Σs = s + x1^2n+1 / (2n+1) s := s.RoundToPrecision(dpcs); // 収束判定の為指定有効桁数以下丸め inc(k); // ループカウンタインクリメント until (last = s) or (k > KK); // 収束判定 ans := two * s; if k > kk then result := false; end; // loge(x) ln(x) // 級数展開 // 1e±500000 程度が限度 // sm <xi< last の範囲外の場合 (0.7~xi~1.4) * 2^nに変換 xiが1に近いほど変換早い function log_big(xi: bigdecimal): bigdecimal; const KK = 10000; var LOG2, SQRT2, two, last, s, sm, one, one1, k2, a: bigdecimal; k : integer; kb, ta : biginteger; dpcs : integer; begin result := '0'; if xi <= result then begin application.MessageBox('無効な値です。','注意',0); exit; end; sm := '1e-2'; last := '5e1'; dpcs := BigDecimal.DefaultPrecision; // 除算演算精度バックアップ one := '1'; if xi = one then begin exit; end; if (xi > sm) and (xi < last) then begin // 0.01 < xi < 50の時はLog11計算 if Log_11(xi, dpcs, a) then begin // log11 result := a; exit; end; end; one1 := '1e500000'; if xi < one then begin // xi < 1 last := one / xi; // 1 / xi if last > one1 then begin // (1 / xi) > 1e500000 application.MessageBox('値が小さすぎます。','注意',0); exit; end; end; if xi > one1 then begin // xi > 1e500000 application.MessageBox('値が大きすぎます。','注意',0); exit; end; xi := xi.RoundToPrecision(dpcs); two := '2'; Log_11(two, dpcs, LOG2); // log(2) SQRT2 := bigdecimal.Sqrt(two, dpcs + dpcs); // √2 k := frexpa(xi / SQRT2, ta); // x / √2 = m * 2^k ta = 2^k kb := k; k2 := ta; // 2^k integer to decimal k2 := k2.RoundToPrecision(dpcs); if k < 0 then begin // kが負数だったら xi := xi * k2; // x * 2^k x=0.707~1.414 √2 xi := xi.RoundToPrecision(dpcs); end else begin xi := xi / k2; // x / 2^k x=0.707~1.414 √2 end; if xi <> one then begin // xi <> 1 なら Log_11(xi, dpcs, s) // log(xi) end else s := '0'; // xi=1なら s=0 result := LOG2 * kb + s; result := result.RoundToPrecision(dpcs); end; //------------------------------------------------------------------------------ // π // https://www.kurims.kyoto-u.ac.jp/~ooura/pi_fft-j.html // T.Ooura AGM アルゴリズ function pi_big: Bigdecimal; var n, dpcs : integer; SQRT_SQRT_EPSILON, c, b, e : BigDecimal; npow : Bigdecimal; a, one, two, four, five, eight : Bigdecimal; begin dpcs := BigDecimal.DefaultPrecision; // 指定精度 + α one := '1'; one := one.RoundToPrecision(dpcs); // oneの有効桁数をdpcsに設定 two := '2'; four := '4'; five := '5'; eight := '8'; SQRT_SQRT_EPSILON := one / BigDecimal.IntPower(two, dpcs shl 1); // 収束判定値 c := BigDecimal.Sqrt(one / eight, dpcs + dpcs); a := one + c + c + c; b := BigDecimal.Sqrt(a, dpcs + dpcs); e := b - five / eight; b := b + b; c := e - c; a := a + e; npow := '4'; n := 0; while (e > SQRT_SQRT_EPSILON) and (n < 100) do begin npow := npow + npow; // 8,16,32,64 e := (a + b) / two; // 平均値 除算有効桁数での丸め b := a * b; b := b.RoundToPrecision(dpcs); // pcs + α 丸め b := BigDecimal.Sqrt(b, dpcs + dpcs); // 平方根有効桁数での丸め e := e - b; b := b + b; c := c - e; a := e + b; inc(n); end; e := e * e; e := e.RoundToPrecision(dpcs); // pcs + α 丸め e := e / four; // e = e * e / 4 a := a + b; result := (a * a - e - e / two) / (a * c - e) / npow; // 除算の順番に注意 result := result.RoundToPrecision(dpcs); // 指定の精度に丸め end; end.
error_or_erfinv_Continued fraction.zip
三角関数、逆三角関数、その他関数 に戻る