2024/03/31  Σ計算のk乗の計算方法を変更し計算の速度向上。
2024/03/01 第3種追加
 第3種は、第2種に 2/(iπ) を乗じるだけなので第2種の計算に追加しました。

xの値が複素数の場合の第2、3種ケルビン関数

 第2種ケルビン関数の計算には、第1種ケルビン関数の計算が必要です。

第2種ケルビン関数

 左の計算式の場合、xの値の実数正の値(0≦X)でないと正しい結果は得られません、虚数iの値は正負問題ありません。
第1種の計算で、非整数の時、複素数の座標で-45°<φ≦45°の間でしか計算できませんでしたが、90°~90°の範囲で計算が出来ます。
第1種の非整数が45°~45°の範囲なのに、それを利用した第2種の計算が-90°<φ≦90°の範囲で正しく計算出来るのが、不思議な感じがします。
 検算に利用しているのは、CASIOの計算サイトです。

第3種ケルビン関数

 計算式はxの値が複素数でない場合と同じですが、kerv(x)、keiv(x) の値がそれぞれ複素数なので注意が必用です。
まず a=herv(x),  b=heiv(x)       (a+ib) / i として先に処理をします。
 (a+ib) / i = b-ia (分母のiを消します)

 her(x)= (2/π)kei(x)
 hei(x)= -(2/π)ker(x)  となります。


 Xの値が複素数の場合、計算値は実数部相当の値も、虚数部相当の値も、複素数となるので答えは、実数部相当の値と、虚数部相当の値を別個に表示します。
Xの値の虚数の値がゼロの場合は、第2,3種ケルビン関数のブログラムを使用してください。
 3rd Kindにチェックを入れると第3種の計算となります、チェックが無ければ第2種です。



プログラム

 プログラムには、二種類の多倍長計算が組み込んでありますが、組み込み方は第1種ケルビン関数v,x実数を参照して下さい。
第2種ケルビン関数の計算に必要な第1種ケルビン関数の計算には第1種ケルビン関数v実数,x複素数の中の三個のうちの最後の計算式が一番計算量が少ないので、それを使用しています。

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  VclTee.TeeGDIPlus, VCLTee.TeEngine, VCLTee.Series, VCLTee.TeeProcs,
  VCLTee.Chart, System.Diagnostics, system.UITypes;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    Chart1: TChart;
    Series1: TLineSeries;
    Series2: TLineSeries;
    Series3: TPointSeries;
    Series4: TPointSeries;
    Series5: TLineSeries;
    Series6: TLineSeries;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    LabeledEdit3: TLabeledEdit;
    CheckBox3: TCheckBox;
    CheckBox4: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private 宣言 }
    procedure chart1coment;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses system.Math, System.VarCmplx, Velthuis.BigIntegers,mp_real, mp_cmplx, mp_types, mp_base;

{$R *.dfm}

type
  DArray = array of double;

var
  xt, yt : Darray;              // x,y データー akima補間用
  m, t    : array of mp_float;  // m,t  akima補間用

  BM : array of mp_float;       // ベルヌーイ数配列
  DG : array of mp_float;       // ディガンマ配列
  FA : array of mp_float;       // 階乗配列
  PVG : array of mp_float;      // +VΓ
  MVG : array of mp_float;      // +VΓ

  zero, one, two, four : mp_float;
  three, pai, log_2pis2 : mp_float;
  gamma : mp_float;

  thirdF : boolean;             // 3rd kind フラグ

const
  KMmax = 250;                  // KM max   250
  Vmax  = 100;                  // v 次数 max
  GL = 9;                       // グラフ計算基本点数

       // オイラー定数 有効桁分用意
       //  0.577215664901532860606512090082402431042159335939923598805767234884867726777664670936947063291746749514631447249807082480960504
       //  01448654283622417399764492353625350033374293733773767394279259525824709491600873520394816567085323315177661152862119950150798479374
  gstr0 = '0.577215664901532860606512090082402431042159335939923598805767234884867726777664670936947063291746749514631447249807082480960504';
  gstr1 = '0144865428362241739976449235362535003337429373377376739427925952582470949160087352039481656708532331517766115286211995015079847';

  gstr = gstr0 + gstr1;

//------------------------------------------------------------------------------
  NB = 120;                            // ベルヌーイ数  配列数 NB + 1

var
  NumeratorString : array[0..NB] of string;               // 分子
  DenominatorString  : array[0..NB] of string;            // 分母

// 最大公約数  ユークリッドの互除法 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];
      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_float);
var
  v, w : mp_float;
  tmp, tmp0, s : mp_float;
  i : integer;
begin
  mpf_init2(v, w);
  mpf_init3(tmp, tmp0, s);

  mpf_set1(v);
  mpf_set_int(tmp, NB);
  while mpf_is_lt(x, tmp) do begin
    mpf_mul(v, x, v);
    mpf_add(x, one, x);
  end;
  mpf_mul(x, x, tmp);               // x^2
  mpf_div(one, tmp, w);             // w = 1 / x^2
  mpf_set0(s);
  for i := NB downto 1 do begin
    mpf_add(s, BM[i], tmp);         // tmp = s + B[i]
    mpf_mul(tmp, w, s);             // s = tmp * w
  end;
  mpf_add(s, BM[0], tmp);           // tmp = s + B[0]
  mpf_div(tmp, x, s);               // s = (s + B[0]) / x
  mpf_add(s, log_2pis2, s);         // s = s + ln(2π)/2
  mpf_ln(v, tmp);                   // ln(v)
  mpf_sub(s, tmp, s);               // s := s - ln(v)
  mpf_sub(s, x, s);                 // s := s - x
  mpf_div(one, two, tmp);           // tmp = 1/2
  mpf_sub(x, tmp, tmp0);            // tmp0 = x - 1/2
  mpf_ln(x, tmp);                   // ln(x)
  mpf_mul(tmp0, tmp, tmp0);         // tmp0 = (x - 1/2) * ln(x)
  mpf_add(s, tmp0, ans);            // ans = s + (x - 1/2) * ln(x)

  mpf_clear2(v, w);
  mpf_clear3(tmp, tmp0, s);
end;

// 多倍長ガンマ
// xの値が 0 と負整数の時Γは∞になるのですが処理をしていませんのでエラーになります。
// ケルビンの次数が整数の時は使用されません。
procedure gammaMul(var x, ans: mp_float);
var
  tmp, tmp0, logG : mp_float;
begin
  mpf_init3(tmp, tmp0, logG);

  if mpf_is_lt(x, zero) then begin
    mpf_mul(pai, x, tmp);            // x*π
    mpf_sin(tmp, tmp0);              // sin(πx);
    mpf_sub(one, x, tmp);            // 1-x
    log_GammaMul(tmp, logG);         // loggamma(1-x);
    mpf_exp(logG, logG);             // exp(logG)
    mpf_div(pai, tmp0, tmp);         // π/sin(πx)
    mpf_div(tmp, logG, ans);         // ans = π/(sin(πx) * logG(1-x))
  end
  else begin
    log_GammaMul(x, logG);           // logG
    mpf_exp(logG, ans);              // exp(logG)
  end;

  mpf_clear3(tmp, tmp0, logG);
end;
//------------------------------------------------------------------------------

// ディガンマ +整数のみ  多倍長
procedure digammaMUL(n: integer;  var ans : mp_float);
var
  s, tmp : mp_float;
  k : integer;
begin
  mpf_init2(s, tmp);

  n := n - 1;
  mpf_set0(s);                              // Σ=0
  mpf_set0(tmp);
  if n >= 0 then begin
    for k := 1 to n do begin
      mpf_set_int(tmp, k);
      mpf_div(one, tmp, tmp);               // 1 / k
      mpf_add(s, tmp, s);
    end;
  end;
  mpf_sub(s, gamma, ans);                   // Σ + γ

  mpf_clear2(s, tmp);
end;
//------------------------------------------------------------------------------

// 階乗 多倍長
procedure factorialMul(n : integer; var ans: mp_float);
label
  EXT;
var
  i : integer;
  bi : mp_float;
begin
  mpf_init(bi);

  mpf_set1(ans);
  mpf_copy(two, bi);
  if n <= 1 then begin
    goto EXT;
  end;
  for i := 2 to n do  begin
    mpf_mul(ans, bi, ans);
    mpf_add(bi, one, bi);
  end;
EXT:
  mpf_clear(bi);
end;

//------------------------------- complex power --------------------------------
// mpc_pow は **.5 時正しい答えを返しません
procedure mpc_powa(x, y : mp_complex; var ans : mp_complex);
var
  ay, ai, harf : mp_float;
begin
  mpf_init3(ay, ai, harf);

  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_div(y.re, four, ay);                       // 4偶数奇数確認
        mpf_frac(ay, ai);                              // 小数部
        if mpf_is0(ai) then mpf_set0(ans.im)           // 偶数なら 虚数部0
                       else mpf_set0(ans.re);          // 奇数なら 実数部0
      end;
    end;
  end;

  mpf_clear3(ay, ai, harf);
end;

//------------------------------------------------------------------------------
// X 値 複素数
// v 次数
// F False berv(z) true beri(z)
procedure berivz(var v : mp_float; var x, ri: mp_complex; F: boolean);
var
  k, j : integer;
  s, x24k, tmp, tmp0, tmp1 : mp_complex;
  kc, xc, xs2: mp_complex;
  kd, nd, vk : mp_float;
  khg, kf : mp_float;
  tmf, tmf0 : mp_float;
  sb : mp_complex;
  piv3s4, kpis2, pis2: mp_float;
  ar, ai, vn : mp_float;
begin
  mpc_init5(s, x24k, tmp, tmp0, tmp1);
  mpc_init3(kc, xc, xs2);
  mpf_init2(khg, kf);
  mpf_init3(kd, nd, vk);
  mpf_init2(tmf, tmf0);
  mpc_init(sb);
  mpf_init3(piv3s4, kpis2, pis2);
  mpf_init3(ar, ai, vn);

  mpf_div(pai, two, pis2);                  // π/2
  mpf_div(pis2, two, tmf);                  // π/4
  mpf_mul(tmf, three, tmf0);                // 3π/4
  mpf_mul(tmf0, v, piv3s4);                 // 3πv/4
  mpc_set0(s);                              // Σ=0
  mpc_set0(sb);
  j := 0;

  mpc_div_mpf(x, two, xs2);                 // x / 2
  mpc_mul(xs2, xs2, xc);                    // (x^2)/ 4
  mpc_set1(x24k);                           // ***
  for k := 0 to KMmax do begin
    mpf_set1(nd);
    mpf_set_int(kf, k);                     // kf = k
    mpf_add(v, kf, tmf0);                   // k + v
    mpf_add(tmf0, one, vk);                 // vk = k + v + 1;
    if mpf_is_lt(vk, zero) then begin       // vk < 0 時 nxが整数か確認
      mpf_int(vk, tmf);                     // int(vk);
      mpf_sub(vk, tmf, nd);                 // vk - int(vk) vkが負の整数だったら vk = 0
    end;
    if mpf_is_ne(vk, zero) and mpf_is_ne(nd, zero) then begin  // vkが負の整数の時は計算しない
      if mpf_is_ge(v, zero) then
        mpf_copy(PVG[k], tmf)
      else
        mpf_copy(MVG[k], tmf);
      mpf_mul(FA[k], tmf, khg);             // k!Γ(n+k+1) vkが0,負の整数の時±∞
//      mpc_set_mpf(kc, kf, zero);            // *** kc = k + 0i  複素数
//      mpc_powa(xc, kc, x24k);                // *** (i(x^2)/4)^k
      mpc_div_mpf(x24k, khg, tmp0);         // ((i(x^2)/4)^k)/(k!Γ(v+k+1))
      mpf_mul(kf, pis2, kpis2);             // kπ/2
      mpf_add(piv3s4, kpis2, tmf);          // 3πv/4 + kπ/2
      if not F then mpf_cos(tmf, tmf0)      // cos(3πv/4 + kπ/2)
               else mpf_sin(tmf, tmf0);     // sin(3πv/4 + kπ/2)
      mpc_mul_mpf(tmp0, tmf0, tmp0);
      mpc_add(s, tmp0, s);                  // Σ
      mpc_sub(s, sb, tmp0);
      if mpc_is0(tmp0) then begin
        inc(j);
        if j > 3 then break;
      end
      else j := 0;
      mpc_copy(s, sb);
    end;
    mpc_mul(x24k, xc, x124k);               // ***
  end;
  mpc_set_mpf(tmp, v, zero);                // v + 0i
  // x が0で次数vが負数の時power演算ゼロでの除算防止
  if mpc_is0(x) and mpf_is_lt(v, zero) then // V<0 x=0 時は無限大になるので計算しない
  else begin
    mpc_powa(xs2, tmp, tmp0);               // (x/2)^v
    mpc_mul(s, tmp0, s);                    // (x/2)^v * Σ
  end;
  mpc_copy(s, ri);

  mpf_abs(x.re, ar);
  mpf_abs(x.im, ai);
  mpf_frac(v, vn);
  // xの実数部と虚数部の絶対値が等しく次数が整数だったら
  if mpf_is_eq(ar, ai) and mpf_is0(vn) then begin
    mpf_div(v, two, ar);
    mpf_frac(ar, ai);
    if mpf_is0(ai) then               // 次数が偶数だったら
      if not F then mpf_set0(ri.im)
               else mpf_set0(ri.re);
  end;

  // xの虚数部がゼロだったら
  if mpf_is0(x.im) then mpf_set0(ri.im);
  // xの実数部がゼロだったら
  if mpf_is0(x.re) and not mpf_is0(x.im) then begin
    mpf_frac(v, ar);
    if mpf_is0(ar) then begin             // 次数整数だったら
      mpf_div(v, two, ai);
      mpf_frac(ai, ar);
      if mpf_is0(ar) then mpf_set0(ri.im)   // 次数偶数だったら
                     else mpf_set0(ri.re);  // 次数奇数だったら
    end
  end;

  mpc_clear5(s, x24k, tmp, tmp0, tmp1);
  mpc_clear3(kc, xc, xs2);
  mpf_clear2(khg, kf);
  mpf_clear3(kd, nd, vk);
  mpf_clear2(tmf, tmf0);
  mpc_clear(sb);
  mpf_clear3(piv3s4, kpis2, pis2);
  mpf_clear3(ar, ai, vn);
end;

// v 非整数
// X 値 複素数
// v 次数
// F False kerv(z) true keri(z)
procedure fractional(var v : mp_float; var x, ri: mp_complex; F: boolean);
var
  bervz, beivz : mp_complex;
  bermv, beimv : mp_complex;
  cosvpi, sinvpi : mp_float;
  tmpc0, tmpc1 : mp_complex;
  tmpf : mp_float;
begin
  mpc_init2(bervz, beivz);
  mpc_init2(bermv, beimv);
  mpf_init3(cosvpi, sinvpi, tmpf);
  mpc_init2(tmpc0, tmpc1);

  berivz(v, x, bervz, false);       // berv(z)
  berivz(v, x, beivz, true);        // beiv(z)

  mpf_chs(v, tmpf);

  berivz(tmpf, x, bermv, false);   // ber-v(z)
  berivz(tmpf, x, beimv, true);    // bei-v(z)

  mpf_mul(v, pai, tmpf);           // vπ
  mpf_cos(tmpf, cosvpi);           // cos(vπ)
  mpf_sin(tmpf, sinvpi);           // sin(vπ)

  if not F then begin
    mpc_mul_mpf(bervz, cosvpi, tmpc0);  // tmpc0 = cos(vπ) berv(z)
    mpc_sub(bermv, tmpc0, tmpc1);       // tmpc1 = ber-v(z) - cos(vπ) berv(z)
    mpc_div_mpf(tmpc1, sinvpi, tmpc0);  // tmpc0 = (ber-v(z) - cos(vπ) berv(z)) / sin(vπ)
    mpc_sub(tmpc0, beivz, tmpc1);       // (ber-v(z) - cos(vπ) berv(z)) / sin(vπ) - beiv(z)
  end
  else begin
    mpc_mul_mpf(beivz, cosvpi, tmpc0);  // tmpc0 = cos(vπ) beiv(z)
    mpc_sub(beimv, tmpc0, tmpc1);       // tmpc1 = bei-v(z) - cos(vπ) beiv(z)
    mpc_div_mpf(tmpc1, sinvpi, tmpc0);  // tmpc0 = (bei-v(z) - cos(vπ) beiv(z)) / sin(vπ)
    mpc_add(tmpc0, bervz, tmpc1);       // (bei-v(z) - cos(vπ) beiv(z)) / sin(vπ) + berv(z)
  end;

  mpc_mul_mpf(tmpc1, pai, tmpc0);               // + pi
  mpc_div_mpf(tmpc0, two, ri);                  // /2

  mpc_clear2(bervz, beivz);
  mpc_clear2(bermv, beimv);
  mpf_clear3(cosvpi, sinvpi, tmpf);
  mpc_clear2(tmpc0, tmpc1);
end;

// v 整数 n
// X 値 複素数
// v 次数
// F False kerv(z) true keri(z)
procedure integers(var v : mp_float; var x, ri: mp_complex; F: boolean);
var
  k, ni, j : integer;
  nd    : double;
  nc : mp_complex;                  // ***
  bervx, beivx : mp_complex;
  xs2, xh2s4, xh2s4hk : mp_complex; // x/2, x^2/4 ,(x^2/4)^k
  pis4 : mp_float;                  // π/4
  lnxs2 : mp_complex;               // ln(x/2)
  mlnxs2berix, pis4berix : mp_complex;        // ln(x/2)berivx, (π/4)berix
  n3s4, ks2,  n3s4Pks2, n3s4Pks2pi: mp_float; // 3n/4, k/2, 3n/4+k/2, (3n/4+k/2)π
  cossin : mp_float;                // cossin((3n/4+k/2)π)
  nmkm1ska : mp_float;              // (n-k-1)1/k!
  psis : mp_float;                  // Ψ(k+1),Ψ(n+k+1), Ψ(k+1)+Ψ(n+k+1)
  kf, khnpkh : mp_float;            // k!(n+k)!
  snm1, sninf, sninfback : mp_complex;    // Σn-1, Σ∞
  tmf0, tmf1, av : mp_float;
  tmc0, tmc1 : mp_complex;
  kernx, keinx : mp_complex;
begin
  mpc_init3(nc, bervx, beivx);       // ***
  mpc_init3(xs2, xh2s4, xh2s4hk);
  mpf_init(pis4);
  mpc_init(lnxs2);
  mpc_iniT2(mlnxs2berix, pis4berix);
  mpf_init4(n3s4, ks2,  n3s4Pks2, n3s4Pks2pi);
  mpf_init3(cossin, nmkm1ska, psis);
  mpf_init2(kf, khnpkh);
  mpc_init3(snm1, sninf, sninfback);
  mpf_init3(tmf0, tmf1, av);
  mpc_init2(tmc0, tmc1);
  mpc_init2(kernx, keinx);

  mpf_abs(v, av);                   // |v|
  nd := mpf_todouble(av);           // v->double nd
  ni := round(nd);                  // nd-> integer ni
  mpc_set_mpf(nc, av, zero);        // v-> cmplex nc
  mpc_div_mpf(x, two, xs2);         // xs2 = x/2
  mpc_mul(xs2, xs2, xh2s4);         // x^2/4 = (x/2)^2
  mpf_div(pai, four, pis4);         // π/4
  mpf_mul(three, av, n3s4);         // 3n           n=v
  mpf_div(n3s4, four, n3s4);        // 3n/4
  mpc_ln(xs2, lnxs2);               // ln(x/2)
  mpc_chs(lnxs2, lnxs2);            // -ln(x/2)
  berivz(av, x, bervx, false);      // bervx
  berivz(av, x, beivx, true);       // berix
  mpc_set1(xh2s4hk);                // ***
  if not F then begin
    mpc_mul(bervx, lnxs2, mlnxs2berix);     // ln(x/2) bervx
    mpc_mul_mpf(beivx, pis4, pis4berix);    // π/4 beivx
    mpc_add(mlnxs2berix, pis4berix, kernx); // kern(x) = -ln(x/2) bervx + π/4 beivx
  end
  else begin
    mpc_mul(beivx, lnxs2, mlnxs2berix);     // ln(x/2) beivx
    mpc_mul_mpf(bervx, pis4, pis4berix);    // π/4 bervx
    mpc_sub(mlnxs2berix, pis4berix, keinx); // kein(x) = -ln(x/2) beivx - π/4 bervx
  end;
  mpc_set0(snm1);
  for k := 0 to ni - 1 do begin
    mpf_set_int(kf, k);                 // mp_float k
    mpf_div(kf, two, ks2);              // k/2
    mpf_add(n3s4, ks2, n3s4Pks2);       // 3n/4 + k/2
    mpf_mul(n3s4Pks2, pai, n3s4Pks2pi); // (3n/4 + k/2)π
    if not F then
      mpf_cos(n3s4Pks2pi, cossin)       // cos(((3n/4 + k/2)π)
    else
      mpf_sin(n3s4Pks2pi, cossin);      // cos(((3n/4 + k/2)π)
//    mpc_set_mpf(kc, kf, zero);          // *** complex k
//    mpc_powa(xh2s4, kc, xh2s4hk);       // *** (x^2/4)^k
    mpf_mul(cossin, FA[ni - k - 1], tmf1);  // cos(((3n/4 + k/2)π) * (n-k-1)!
    mpf_div(tmf1, FA[k], tmf1);         // cos(((3n/4 + k/2)π) * (n-k-1)! / k!
    mpc_mul_mpf(xh2s4hk, tmf1, tmc0);   // cosαβ * (x^2/4)^k
    mpc_add(snm1, tmc0, snm1);          // Σ1
    mpc_mul(xh2s4hk, xh2s4, xh2s4hk);   // ***
  end;
  mpc_chs(nc, tmc0);                    // -n
  mpc_powa(xs2, tmc0, tmc1);            // (x/2)^-n
  mpc_mul(snm1, tmc1, snm1);            // Σ1 * (x/2)^-n
  mpc_div_mpf(snm1, two, snm1);         // Σ1 * (x/2)^-n / 2

  j := 0;
  mpc_set0(sninf);
  mpc_set0(sninfback);
  mpc_set1(xh2s4hk);                // ***
  for k := 0 to KMmax do begin
    mpf_set_int(kf, k);                 // mp_float k
    mpf_div(kf, two, ks2);              // k/2
    mpf_add(n3s4, ks2, n3s4Pks2);       // 3n/4 + k/2
    mpf_mul(n3s4Pks2, pai, n3s4Pks2pi); // (3n/4 + k/2)π
    if not F then
      mpf_cos(n3s4Pks2pi, cossin)       // cos(((3n/4 + k/2)π)
    else
      mpf_sin(n3s4Pks2pi, cossin);      // sin(((3n/4 + k/2)π)
//    mpc_set_mpf(kc, kf, zero);          // *** complex k
//    mpc_powa(xh2s4, kc, xh2s4hk);       // *** (x^2/4)^k
    mpf_copy(DG[ni + k + 1], tmf0);     // Ψ(n+k+1)
    mpf_add(DG[k + 1], tmf0, psis);     // psis = Ψ(k+1)+Ψ(n+k+1)
    mpf_mul(FA[k], FA[ni + k], khnpkh); // k!(n+k)!
    mpf_mul(cossin, psis, tmf0);        // cos or sin(((3n/4 + k/2)π) * (Ψ(k+1)+Ψ(n+k+1))
    mpf_div(tmf0, khnpkh, tmf1);        // cos or sin α/ (k!(n+k)!)
    mpc_mul_mpf(xh2s4hk, tmf1, tmc0);   // cos or sin αβ * (x^2/4)^k
    mpc_add(sninf, tmc0, sninf);        // Σ2
    mpc_sub(sninf, sninfback, tmc1);    // 収束判定 収束=tmc1
    if mpc_is0(tmc1) then inc(j)
                     else j := 0;
    if j > 2 then break;
      mpc_copy(sninf, sninfback);
    mpc_mul(xh2s4hk, xh2s4, xh2s4hk);   // *** 
  end;
  mpc_powa(xs2, nc, tmc1);              // (x/2)^n
  mpc_mul(sninf, tmc1, sninf);          // Σ2 * (x/2)^n
  mpc_div_mpf(sninf, two, sninf);       // Σ2 * (x/2)^n/2

  if not F then
    mpc_add(kernx, snm1, tmc0)          // A + Σ1
  else
    mpc_sub(keinx, snm1, tmc0);         // A - Σ1

  mpc_add(tmc0, sninf, ri);             // A + or - Σ1 + Σ2

  // v<0 なら -1^|v| * ri
  if (not s_mpf_is_ge0(v)) and (ni mod 2 <> 0) then mpc_chs(ri, ri);

  mpc_clear3(nc, bervx, beivx);         // ***
  mpc_clear3(xs2, xh2s4, xh2s4hk);
  mpf_clear(pis4);
  mpc_clear(lnxs2);
  mpc_clear2(mlnxs2berix, pis4berix);
  mpf_clear4(n3s4, ks2,  n3s4Pks2, n3s4Pks2pi);
  mpf_clear3(cossin, nmkm1ska, psis);
  mpf_clear2(kf, khnpkh);
  mpc_clear3(snm1, sninf,  sninfback);
  mpf_clear3(tmf0, tmf1, av);
  mpc_clear2(tmc0, tmc1);
  mpc_clear2(kernx, keinx);
end;

// 整数非整数
// X 値 複素数
// v 次数
// 第2種 F False kerv(z) true keri(z)
// thirdF False 第2種 true 第3種
// 第3種 2/(iπ) * (kerv + ikeiv)
procedure kerviz(var v : mp_float; var x, ri: mp_complex; F: boolean);
var
  vi, twospi : mp_float;
begin
  mpf_init2(vi, twospi);

  mpf_div(two, pai, twospi);            // 2/π

  mpf_frac(v, vi);                      // vの 小数部vi

  // 第3種の場合実数相当部と虚数部相当部入れ替えて計算します  2/(iπ) * (kerv + ikeiv)
  // 1/(0+i) * (kerv + ikeiv) の処理  虚数相当部と実数相当部が入れ替わります
  // (kerv + ikeiv)/(0+i) -> (kerv + ikeiv)i/((0+i)i) -> (ikerv - keiv)/-1
  // -> (keiv - ikerv)  ※ (keiv - ikerv) * 2/π
  // ※  herv = keiv * 2/π   heiv = -kerv * 2/π
  if thirdF then if F then F := False     // 第3種だったら実数虚数部フラグ反転
                      else F := True;     // 虚数部と実数部入れ替え
  if mpf_is0(vi) then integers(v, x, ri, F)     // 整数計算
                 else fractional(v, x, ri, F);  // 非整数計算
  if thirdF then begin                    // 第3種だったら
    mpc_mul_mpf(ri, twospi, ri);          // 2/π 乗算
    if not F then mpc_chs(ri, ri);        // 第三種の場合フラグ反転に注意 虚数相当部の符号反転
  end;

  mpf_clear2(vi, twospi);
end;

// akima m,t テーブル作成
// x[] xデーター配列
// y[] yデーター配列
// m[] m係数テーブル
// t[] t係数テーブル
procedure akima_table;
var
  ii, n : integer;
  a, b, half, tmf, tmf0 : mp_float;
  ytm, xtm : array of mp_float;
  tmf1 : mp_float;
begin
  n := high(xt) + 1;
  setlength(ytm, n);
  setlength(xtm, n);
  for ii := 0 to n - 1 do begin
    mpf_init(ytm[ii]);
    mpf_init(xtm[ii]);
  end;

  mpf_init5(a, b, half, tmf, tmf0);
  mpf_init(tmf1);

  mpf_set_dbl(half, 1 / 2);
//  mpf_set_int(tow, 2);
//  mpf_set0(zero);

  for ii := 0 to n -1 do begin
    mpf_set_dbl(xtm[ii], xt[ii]);
    mpf_set_dbl(ytm[ii], yt[ii]);
  end;

  // shift data by + 2 in the array and compute the secants
  // also calculate extrapolated and end point secants
  // 傾斜α両端を除く  Δy/Δx
  for ii := 0 to n - 2 do begin
    mpf_sub(ytm[ii + 1], ytm[ii], tmf);
    mpf_sub(xtm[ii + 1], xtm[ii], tmf0);
    mpf_div(tmf, tmf0, m[ii + 2]);
  end;
//  for ii := 0 to n - 2 do
//    m[ii + 2] := (yt[ii + 1] - yt[ii]) / (xt[ii + 1] - xt[ii]);
  // 端点傾斜処理
  mpf_mul(two, m[2], tmf);
  mpf_sub(tmf, m[3], m[1]);
//  m[1] := 2 * m[2] - m[3];
  mpf_mul(two, m[1], tmf);
  mpf_sub(tmf, m[2], m[0]);
//  m[0] := 2 * m[1] - m[2];
  mpf_mul(two, m[n], tmf);
  mpf_sub(tmf, m[n - 1], m[n + 1]);
//  m[n + 1] := 2 * m[n] - m[n - 1];
  mpf_mul(two, m[n + 1], tmf);
  mpf_sub(tmf, m[n], m[n + 2]);
//  m[n + 2] := 2 * m[n + 1] - m[n];
  // 各ポイントの傾斜係数計算
  for ii := 0 to n - 1 do begin
    mpf_sub(m[ii + 3],m[ii + 2],tmf0);
    mpf_abs(tmf0, a);
//    a := abs(m[ii + 3] - m[ii + 2]);
    mpf_sub(m[ii + 1], m[ii], tmf0);
    mpf_abs(tmf0, b);
//    b := abs(m[ii + 1] - m[ii]);
    mpf_add(a, b, tmf1);
    if mpf_is_ne(tmf1, zero) then begin
      mpf_mul(a, m[ii + 1], tmf);
      mpf_mul(b, m[ii + 2], tmf0);
      mpf_add(tmf, tmf0, tmf);
      mpf_div(tmf, tmf1, t[ii]);
    end
    else begin
      mpf_add(m[ii + 2], m[ii + 1], tmf);
      mpf_mul(half, tmf, t[ii]);
    end;
{
    if (a + b) <> 0 then begin
      t[ii] := (a * m[ii + 1] + b * m[ii + 2]) / (a + b);
    end
    else
      t[ii] := half * (m[ii + 2] + m[ii + 1]);
}
  end;

  for ii := 0 to n - 1 do begin
    mpf_clear(ytm[ii]);
    mpf_clear(xtm[ii]);
  end;

  mpf_clear5(a, b, half, tmf, tmf0);
  mpf_clear(tmf1);
end;

// akima 補間値計算
// xx xの値
// x[] xデーター配列
// y[] yデーター配列
// m[] m係数テーブル
// t[] t係数テーブル
// result 補間値y'
function akima_Interpolation(xx: double): double;
var
  iB, iM, iT: integer;
  a, b, tmf, tmf0 : mp_float;
  c, d, e, f, tmf1 : mp_float;
  three : mp_float;
begin
  mpf_init4(a, b, tmf, tmf0);
  mpf_init5(c, d, e, f, tmf1);
  mpf_init(three);

  mpf_set_int(three, 3);

  iB := low(xt);                       // x[] bottom 配列no
  iT := high(xt);                      // x[] top配列No
  // xx値の上下の配列xの配列番号を探す
  // XX<x[iB]の場合一番下の区間 XX>x[iT]の場合一番上の区間
  while (iT - iB) > 1 do begin
    iM := (iB + iT) div 2;            // middle配列no
    if xt[iM] > xx then
      iT := iM
    else
      iB := iM;
  end;
  mpf_set_dbl(b, xt[iT] - xt[iB]);
//  b := xt[iT] - xt[iB];                 // 区間のxの変化量
  mpf_set_dbl(a, xx - xt[iB]);
//  a := xx - xt[iB];                     // x[iB]からのxの値
  // 3次akima spline 計算
  mpf_set_dbl(c, yt[iB]);               // c = yt[ib]
  mpf_mul(t[iB], a, d);                 // d = t[ib] * a
  mpf_mul(three, m[iB + 2], tmf);       // 3 * m[iB + 2]
  mpf_mul(two, t[ib], tmf0);            // 2 * t[iB]
  mpf_sub(tmf, tmf0, tmf1);             // 3 * m[iB + 2] - 2 * t[iB]
  mpf_sub(tmf1, t[iB + 1], tmf);        // 3 * m[iB + 2] - 2 * t[iB] - t[iB + 1]
  mpf_mul(tmf, a, tmf);                 // (3 * m[iB + 2] - 2 * t[iB] - t[iB + 1]) * a
  mpf_mul(tmf, a, tmf);                 // (3 * m[iB + 2] - 2 * t[iB] - t[iB + 1]) * a * a
  mpf_div(tmf, b, e);                   // (3 * m[iB + 2] - 2 * t[iB] - t[iB + 1]) * a * a / b
  mpf_add(t[iB], t[iB + 1], tmf);       // t[iB] + t[iB + 1]
  mpf_mul(two, m[iB + 2], tmf0);        // 2 * m[iB + 2]
  mpf_sub(tmf, tmf0, tmf);              // t[iB] + t[iB + 1] - 2 * m[iB + 2]
  mpf_mul(tmf, a, tmf);                 // (t[iB] + t[iB + 1] - 2 * m[iB + 2]) * a
  mpf_mul(tmf, a, tmf);                 // (t[iB] + t[iB + 1] - 2 * m[iB + 2]) * a * a
  mpf_mul(tmf, a, tmf);                 // (t[iB] + t[iB + 1] - 2 * m[iB + 2]) * a * a * a
  mpf_mul(b, b, tmf0);                  // b * b
  mpf_div(tmf, tmf0, f);                // (t[iB] + t[iB + 1] - 2 * m[iB + 2]) * a * a * a / (b * b)
  mpf_add(c, d, tmf);                   // c + d
  mpf_add(tmf, e, tmf);                 // c + d + e
  mpf_add(tmf, f, tmf);                 // c + d + e + f

  result := mpf_todouble(tmf);
{
  result :=   yt[iB]
            + t[iB] * a
            + (3 * m[iB + 2] - 2 * t[iB] - t[iB + 1]) * a * a / b
            + (t[iB] + t[iB + 1] - 2 * m[iB + 2]) * a * a * a / (b * b);
}

  mpf_clear4(a, b, tmf, tmf0);
  mpf_clear5(c, d, e, f, tmf1);
  mpf_clear(three);

end;

procedure ChartBackclear;           // ***
begin
  with Form1.Chart1.BackImage.Bitmap.Canvas do begin
    Brush.Color := clBtnFace;
    Brush.Style := bsSolid;
    FillRect(rect(0, 0, Form1.Chart1.Width, Form1.Chart1.Height));
    Brush.Style := bsClear;
  end;
end;

procedure TForm1.chart1coment;      // ***
begin
  with Form1.Chart1.BackImage.Bitmap.Canvas do begin
    Font.Size := 8;
    Font.Style := [];
    Font.Color := clred;
    TextOut(chart1.Width - 30, 1,'実数');
    Font.Color := clblue;
    TextOut(chart1.Width - 30, 13,'虚数');
    Pen.Width := 1;
    Pen.Color := clred;
    MoveTo(chart1.Width - 50, 6);
    LineTo(chart1.Width - 32, 6);
    Pen.Color := clblue;
    MoveTo(chart1.Width - 50, 18);
    LineTo(chart1.Width - 32, 18);
  end;
end;

// 計算
// xの値が大きくなると誤差が大きくなります。
// x実数の値がX<0の時は正しい値がでません
// ta[]グラフ用計算点
procedure TForm1.Button1Click(Sender: TObject);
label
  EXT;
const
  x0m = 1e-50;        // ゼロ近傍値 infinty の符号設定計算値
  ta : array[0..GL - 1] of double = (0.08, 0.14, 0.23, 0.46, 0.86, 1.5, 2.5, 3.2, 4);
  YPM = 1E304;        // Double 演算オーバーフロー対策 最大値制限値
  YMM = - YPM;
  zeromg = '1E-90';   // 計算結果表示これより小さい値は0にします 演算桁数の1/2
var
  ch, i, xi: integer;
  kerx, keix: double;
  kerxe, keixe: double;
  xin, vin, xv : double;
  xmin, xmax, dx, dxf : double;
  ymin, ymax: double;
  kerl : Darray;
  keil : Darray;
  xl   : Darray;
  xm, vm, xvm, ixm: mp_float;
  nd, tmf : mp_float;
  ri : mp_complex;
  StopWatch : TStopwatch;
  ElapsedMillseconds : Int64;
  mm, ss, ms : integer;
  xc, xcb, dxc : mp_complex;
  GS : integer;       // xv = 0 がない場合 推定点数
  k : integer;
  vk, avm, tmf0, zz : mp_float;
  ix : double;
  istr : string;
  F : boolean;
  // double to mpc  グラフ計算用
  procedure xvtoXc(xv, ia : double; var xc : mp_complex);
  begin
    mpf_set_dbl(xvm, xv);
    mpf_set_dbl(tmf, ia);
    mpc_set_mpf(xc, xvm, tmf);
  end;

  function maxmin(x : double): double;
  begin
    result := x;
    if x > YPM then result := YPM;
    if x < YMM then result := YMM;
  end;

begin
  memo1.Clear;
  val(labelededit1.Text, vin, ch);
  if ch <> 0 then begin
    application.MessageBox('次数vの値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(vin) > Vmax then begin
    application.MessageBox('次数vの値が計算範囲外です。','注意', 0);
    exit;
  end;
  val(labelededit2.Text, xin, ch);
  if ch <> 0 then begin
    application.MessageBox('xの値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(xin) > 100 then begin
    application.MessageBox('xが100を越えると条件によって誤差が大きくなります。','注意', 0);
  end;
  val(labelededit3.Text, ix, ch);
  if ch <> 0 then begin
    application.MessageBox('i の値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(ix) > 100 then begin
    application.MessageBox('iが100を越えると条件によって誤差が大きくなります。','注意', 0);
  end;
  xmin := 0;
  if xin < 0 then begin
    istr := 'xの値がx≧0でないと' + #13#10 +
            '正しい答えが得られません計算を中断しますか';
    if MessageDlg(istr , mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrYes then exit;
    xmin := xin - 0.1;
  end;

  mpf_init4(xm, vm, xvm, ixm);
  mpf_init3(nd, tmf, zz);
  mpf_init3(vk, avm, tmf0);
  mpc_init4(ri, xc, xcb, dxc);
  ChartBackclear;                                          // ***

  F := False;                                              // kerx 計算
  if Checkbox3.Checked = true then F := true;              // keix 計算

  if checkbox4.Checked = true then begin
    thirdF := true;
    Chart1.Title.Caption := 'Kelvin functions complex of 3rd kind';
  end
  else begin
    thirdF := false;
    Chart1.Title.Caption := 'Kelvin functions complex of 2nd kind';
  end;

  mpf_set0(ixm);

  mpf_read_decimal(vm, PAnsiChar(ansistring(labelededit1.Text + #00)));
  mpf_read_decimal(xm, PAnsiChar(ansistring(labelededit2.Text + #00)));
  mpf_read_decimal(ixm, PAnsiChar(ansistring(labelededit3.Text + #00)));
  mpf_read_decimal(zz, PAnsiChar(ansistring(zeromg + #00)));

  mpc_set_mpf(xcb, xm, ixm);                   // xcb 計算用 xの複素数

  series1.Clear;
  series2.Clear;
  series3.Clear;
  series4.Clear;

  if ix >= 0 then istr := ' +' + floatTostr(ix) + 'i'
             else istr := ' ' + floatTostr(ix) + 'i';
  memo1.Lines.Append('n = ' + floatTostr(vin) + '  x = ' + floatTostr(xin) + istr);

  application.ProcessMessages;

  mpf_abs(vm, avm);
  for k := 0 to KMmax do begin
    mpf_set_int(tmf, k);                    // k
    mpf_add(tmf, avm, tmf0);                // v + k
    mpf_add(tmf0, one, vk);                 // vk= v + k + 1
    gammaMul(vk, PVG[k]);                   // Γ(n+k+1)
  end;
  mpf_chs(avm, avm);                        // -v
  for k := 0 to KMmax do begin
    mpf_set1(nd);
    mpf_set_int(tmf, k);                    // k
    mpf_add(tmf, avm, tmf0);                // -v + k
    mpf_add(tmf0, one, vk);                 // vk= -v + k + 1
    if mpf_is_lt(vk, zero) then begin       // vk < 0 時 nxが整数か確認
      mpf_int(vk, tmf);                     // int(vk);
      mpf_sub(vk, tmf, nd);                 // vk - int(vk) vkが負の整数だったら nd = 0
    end;
    if mpf_is_ne(vk, zero) and mpf_is_ne(nd, zero) then // vkが負の整数の時は計算しない
      gammaMul(vk, MVG[k])                  // Γ(n+k+1)
    else
      mpf_set0(MVG[k]);                     // Γ(n+k+1) = 0
  end;

  StopWatch := TStopwatch.StartNew;

  kerxe := 0;
  keixe := 0;
  // 表示値の計算
  if not mpc_is0(xcb) then begin
    kerviz(vm, xcb, ri, F);                        // xcb 複素数
    kerxe := mpf_todouble(ri.re);
    keixe := mpf_todouble(ri.im);
    if checkbox3.Checked = false then begin
      if not thirdF then
        memo1.Lines.Append( string('kerv(x) = ' + mpf_decimal(ri.re, 50)))      // 数値表示
      else
        memo1.Lines.Append( string('herv(x) = ' + mpf_decimal(ri.re, 50)));     // 数値表示
      if not mpf_is0(ixm) then
        memo1.Lines.Append( string('     i = ' + mpf_decimal(ri.im, 50)));      // 数値表示
    end
    else begin
      if not thirdF then
        memo1.Lines.Append( string('keiv(x) = ' + mpf_decimal(ri.re, 50)))      // 数値表示
      else
        memo1.Lines.Append( string('heiv(x) = ' + mpf_decimal(ri.re, 50)));     // 数値表示
      if not mpf_is0(ixm) then
        memo1.Lines.Append( string('     i = ' + mpf_decimal(ri.im, 50)));      // 数値表示
    end;
  end
  // xc=0  v > 0  の場合 r ±∞ i ±∞
  // xc=0   v = 0 の場合 r ∞ i -π/4
  // xc=0   v = 0 の場合 r 0.5 i ∞
  else begin
    mpc_set_dbl(dxc, x0m, 0);
    kerviz(vm, dxc, ri, F);                        // dxc 複素数  0近傍計算

    if s_mpf_is_ge0(ri.re) then kerxe := infinity
                           else kerxe := -infinity;
    if s_mpf_is_ge0(ri.re) then keixe := infinity       // ri.im は x の虚数部が0でないとき
                           else keixe := -infinity;
    if mpf_is0(vm) then begin                           // v=0
      if not thirdF then begin
        if checkbox3.Checked = false then begin
          kerxe := infinity;
          memo1.Lines.Append('kerv(x) = ' + floattostr(kerxe));       // 数値表示
        end
        else begin
          mpf_div(pai, four, tmf);
          mpf_chs(tmf, tmf);
          keixe := -pi / 4;
          memo1.Lines.Append('keiv(x) = ' + string(mpf_decimal(tmf, 50)));      // 数値表示
        end;
      end
      else begin
        if checkbox3.Checked = false then begin
          mpf_div(one, two, tmf);
          mpf_chs(tmf, tmf);
          memo1.Lines.Append('herv(x) = ' + string((mpf_decimal(tmf, 50))));       // 数値表示
        end
        else begin
          keixe := -infinity;
          memo1.Lines.Append('heiv(x) = ' + floattostr(keixe));      // 数値表示
        end;
      end;
    end
    else begin                                          // v <> 0
      mpf_abs(vm, tmf);
      if mpf_is_eq(tmf, two) then begin                 // v = 2
        if not thirdF then begin
          kerxe := 0.5;
          keixe := infinity;
          if checkbox3.Checked = false then                 // V-2, V<>0
            memo1.Lines.Append('kerv(x) = ' + floattostr(kerxe))       // 数値表示
          else
            memo1.Lines.Append('keiv(x) = ' + floattostr(keixe));       // 数値表示
        end
        else begin
          kerxe := infinity;
          mpf_div(one, pai, tmf);
          mpf_chs(tmf, tmf);
          if checkbox3.Checked = false then                 // V-2, V<>0
            memo1.Lines.Append('herv(x) = ' + floattostr(kerxe))       // 数値表示
          else
            memo1.Lines.Append('herv(x) = ' + string((mpf_decimal(tmf, 50))));       // 数値表示
        end;
      end
      else begin
        if not thirdF then begin
          if checkbox3.Checked = false then                 // V-2, V<>0
            memo1.Lines.Append('kerv(x) = ' + floattostr(kerxe))       // 数値表示
          else
            memo1.Lines.Append('keiv(x) = ' + floattostr(keixe));       // 数値表示
        end
        else begin
          if checkbox3.Checked = false then                 // V-2, V<>0
            memo1.Lines.Append('herv(x) = ' + floattostr(kerxe))       // 数値表示
          else
            memo1.Lines.Append('heiv(x) = ' + floattostr(keixe));       // 数値表示
        end;
      end;
    end;
  end;

  StopWatch.Stop;
  ElapsedMillseconds := StopWatch.ElapsedMilliseconds;

  ms := ElapsedMillseconds * (GL + 1) * 2 + 1000;                     // ***
  mm := ms div 60000;
  ss := (ms mod 60000) div 1000;
  memo1.Lines.Append('グラフ表示に約' + inttostr(mm) + '分' + inttostr(ss) + '秒必要です。');

  if checkbox2.Checked = true then begin          // グラフ無だったら終了
    Chart1.Canvas.Font.Style := [fsBold];
    Chart1.Canvas.Font.size := 8;
    Chart1.Canvas.TextOut(170, 115,'グラフ無し');
    goto EXT;
  end;

  // 最大値最小値の検索とグラフデーター作成
  xi := Trunc(xin);
//  xmin := 0;
  if xi > 4 then xmin := xi - 4;
  xmax := xmin + 8;
  setlength(kerl, GL + GL);
  setlength(keil, GL + GL);
  setlength(xt, GL + GL); setlength(yt, GL + GL);
  setlength(xl, GL + GL);
  dxf := 0.1;
  dx  := 0.1;
  dx := (xmax - xmin) / (Gl + GL - 1);
  for i := 0 to GL + GL - 1 do xl[i] := dx * i + xmin;
  xl[0] := xl[0] + dxf;
  xl[GL + GL - 1] := xl[GL + GL - 1] - dxf;
  GS := 80;
  // グラフ用データー作成
  ymin := 0;
  ymax := 0;
  for i := 0 to GL + GL - 1 do begin
    xv := xl[i];
    xvtoxc(xv, ix, xc);
    kerviz(vm, xc, ri, F);
    kerl[i] := maxmin(mpf_todouble(ri.re));
    keil[i] := maxmin(mpf_todouble(ri.im));
    if kerl[i] > ymax then ymax := kerl[i];
    if keil[i] > ymax then ymax := keil[i];
    if kerl[i] < ymin then ymin := kerl[i];
    if keil[i] < ymin then ymin := keil[i];
  end;

  // 指定値の値制御
  if kerxe > ymax then kerxe := ymax;
  if kerxe < ymin then kerxe := ymin;
  if keixe > ymax then keixe := ymax;
  if keixe < ymin then keixe := ymin;

  series3.AddXY(xin, kerxe);              // 実数部計算点ドット
  if not mpf_is0(ixm) then                // 虚数部0だったら虚数ドット無し
    series4.AddXY(xin, keixe);

  if checkbox1.Checked = true then begin
    for  i := 0 to GL + GL - 1 do series1.AddXY(xl[i], kerl[i]);
    if not mpf_is0(ixm) then              // 虚数部0だったら虚数部グラフ無し
      for  i := 0 to GL + GL - 1 do series2.AddXY(xl[i], keil[i]);
  end;

  if checkbox1.Checked = false then begin
  // グラフ計算
    for  i := 0 to GL + GL - 1 do begin
      xt[i] := xl[i];
      yt[i] := kerl[i];
    end;
    akima_table;
    dx := (xt[GL + GL - 1] - xt[0]) / GS;
    for i := 0 to GS do begin
      xv := dx * i + xt[0];
      kerx := maxmin(akima_Interpolation(xv));
      series1.AddXY(xv, kerx);
    end;
    if not mpf_is0(ixm) then begin        // 虚数部0だったら虚数部グラフ無し
      for  i := 0 to GL + GL - 1 do yt[i] := keil[i];
      akima_table;
      for i := 0 to GS do begin
        xv := dx * i + xt[0];
        keix := maxmin(akima_Interpolation(xv));
        series2.AddXY(xv, keix);
      end;
    end;
  end;
  application.ProcessMessages;
  chart1coment;
EXT:
  mpf_clear4(xm, vm, xvm, ixm);
  mpf_clear3(nd, tmf, zz);
  mpc_clear4(ri, xc, xcb, dxc);
  mpf_clear3(vk, avm, tmf0);
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  i : integer;
  N, D, tmp : mp_float;
  bt : Tbitmap;                   // *** 
begin
  mpf_set_default_decprec(180);         // 有効桁数180桁 50桁の精度に必要です。
  setlength(BM, NB + 1);                // ベルヌーイ数配列
  setlength(DG, KMmax + Vmax + 2);      // ディガンマ
  setlength(FA, KMmax + Vmax + 1);      // K1配列
  setlength(PVG, KMmax + 1);            // +vΓ
  setlength(MVG, KMmax + 1);            // -vΓ
  setlength(t, GL + GL);                // akima 補間値計算 配列 t
  setlength(m, GL + GL + 3);            // akima 補間値計算 配列 m


  for i := 0 to NB do mpf_init(BM[i]);
  for i := 0 to KMmax + Vmax + 1 do mpf_init(DG[i]);
  for i := 0 to KMmax + Vmax do mpf_init(FA[i]);
  for i := 0 to KMmax do mpf_init(PVG[i]);
  for i := 0 to KMmax do mpf_init(MVG[i]);

  for i := 0 to GL + GL - 1 do mpf_init(t[i]);
  for i := 0 to GL + GL + 2 do mpf_init(m[i]);

  mpf_init3(N, D, tmp);
  mpf_init4(zero, one, two, four);
  mpf_init3(three, pai, log_2pis2);
  mpf_init(gamma);
  mpf_read_decimal(gamma, PAnsiChar(ansistring(gstr + #00)));     // γ

  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_mul(pai, two, tmp);          // 2π
  mpf_ln(tmp, tmp);                // ln(2π)
  mpf_div(tmp, two, log_2pis2);    // ln(2π)/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]);
  end;

  for i := 0 to KMmax + Vmax + 1 do begin
    digammaMUL(i, D);
    mpf_copy(D, DG[i]);
  end;

  for i := 0 to KMmax + Vmax do begin
    factorialMul(i, N);
    mpf_copy(N, FA[i]);
  end;

  memo1.Clear;

  bt := Tbitmap.Create;                       // ***
  bt.Width := Chart1.Width;
  bt.Height := Chart1.Height;
  Chart1.BackImage.Bitmap := bt;
  bt.Free;

  ChartBackclear;                             // ***

  mpf_clear3(N, D, tmp);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  i : integer;
begin
  for i := 0 to NB do mpf_clear(BM[i]);
  for i := 0 to KMmax + Vmax + 1 do mpf_clear(DG[i]);
  for i := 0 to KMmax + Vmax do mpf_clear(FA[i]);
  for i := 0 to KMmax do mpf_clear(PVG[i]);
  for i := 0 to KMmax do mpf_clear(MVG[i]);
  for i := 0 to GL + GL - 1 do mpf_clear(t[i]);
  for i := 0 to GL + GL + 2 do mpf_clear(m[i]);
  mpf_clear4(zero, one, two, four);
  mpf_clear3(three, pai, log_2pis2);
  mpf_clear(gamma);
end;

end.


download kelvin_function_Complex_of_2nd_3rd_kind.zip

  三角関数、逆三角関数、その他関数 に戻る