2024/03/25 多倍長演算のルーチンを見直し演算の速度を早くしました。
2024/03/20 多倍長計算のMVG, PVGの配列の長さを修正しました。
2023/10/13 複素数の計算ができるプログラムを追加しました、又、多倍長演算とし、50桁の精度で答えがでる様にしてみました。
2021/09/19 第1種ベッセル関数の計算精度の向上を図ったので、第2種ベッセル関数の検討もしてみました。
        次数が実数の場合は、第1種ベッセル関数が使用されるのですが、第2種の整数の場合、第1種と他の計算の差分となり、第2種変形ベッセル関数では全く使用されません。
        次数が実数の計算のみ精度の向上が繁栄され、整数の場合は、従来の計算の方が、精度が高くります。
2020/07/01 次数がマイナスの値の時を考慮していませんでしたので修正しました。

第2種ベッセル関数

 第1種ベッセル関数を取り上げたので、第2種ベッセル関数についても取り上げました。
ベッセル関数の詳細は、インターネットで参照してください。

 第2種ベッセル関数の計算は、次数が α 実数の場合と、n 整数の場合に分けて計算します。
Yα(x)とKα(x)の計算の場合、α が整数の場合、分母がゼロに成ってしまう為、整数用のYn(z)、Kn(z)の計算をします。
次数が整数の場合、計算にディガンマ関数が必用となります。
この場合、ディガンマ関数は、整数のみしか使用されないので、整数用のディガンマ関数を使用すればプログラムは簡単になります。
第2種ベッセル関の計算には、第1種ベッセル関数の計算が必要で、次数が実数の場合は、Γ関数が使用されているので、階乗!はΓ関数を使用すれば良いでしょう。

 次数がマイナスの整数となるときは、左図の関係式となります。


 左図は、第2種ベッセル関数の次数が整数時のグラフです。
次数が整数なので、第1種ベッセル関数も整数用のルーチンが使用されています。
下側は、第2種変形ベッセル関数です。
変形ベッセル関数には、確認の為、少しルーチンが違う二つのプロぎラムを入れてあります。
 ∑値の計算で、m=0~∞となっている場所がありますが、Doubleの精度の場合、171以上の値の階乗でオーバーフローします。
Doubleの精度であれば、m=0~30程度の計算で問題ないようです。
プログラムでは50迄計算しています。
 また、Xの値が大きくなると、演算有効桁数の不足により、誤差が大きくなり正しい結果が得られなくなります。




プログラム
 次はプログラムは、次数が正の整数の場合のプログラムです。

// Xの値 積分計算の上限値MNによってオーバーフローを発生するので
// コンパイル設定にオーバーフローチックが必須です。
unit Main;

interface

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

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Memo1: TMemo;
    LabeledEdit1: TLabeledEdit;
    Chart1: TChart;
    Series1: TLineSeries;
    CheckBox1: TCheckBox;
    Series2: TLineSeries;
    Series3: TLineSeries;
    CheckBox2: TCheckBox;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    function NnX(x: double; n: integer): double;
    procedure GraphNnX(xmax:double; n: integer);
    function KnXa(x: double; n: integer): double;
    function KnXb(x: double; n: integer): double;
    procedure GraphKnX(xmax:double; n: integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  gamma = 0.57721566490153286060651209008240243104215;  // オイラー定数

// 階乗 m!
function factorial(m: integer): double;
var
  i : integer;
  J : double;
begin
  j := 1;
  for i := 2 to m do j := j * i;
  result := j;
end;

// 第一種ベッセル関数
// X 値
// N 次数
// flag false 通常 true 変形
// Mの値は積分上は∞となっていますが精度上50程度で問題ないようです。
function Bessel(X: double; N: integer;  flag: boolean): double;
const
  M = 50;                                   // 値を大きくするとオーバーフローします。
var
  J, K: Integer;
  B, S, Jf: double;
begin
  B := 1.0;
  if N > 1 then begin
    for K := 1 to N do B := B / K;
  end;
  S := B * power((X / 2), N);
  for J := 1 to M do begin
    Jf := J;                                // オバーフロー対策で浮動小数点使用します。
    B := B / (Jf * (Jf + N));
    if not flag then
      S := S + power(-1, J) * B * power(X / 2, 2 * J + N)
    else
      S := S + B * power(X / 2, 2 * J + N)
  end;
  result := S;
end;

// Ψ(p) ディガンマ関数
function phiN(n: integer): double;
var
  i: integer;
  s: double;
begin
  if n <= 0 then begin
    result := 0;
    exit;
  end;
  if n = 1 then begin
     result := - gamma;
     exit;
  end;
  s := 0;
  for i := 1 to n - 1 do begin
    s := s + 1 / i;
  end;
  result := s - gamma;
end;


// 第二種ベッセル関数
// X 値
// n 次数
// Mの値は積分上は∞となっていますが精度上50程度で問題ないようです。
function TForm1.NnX(x: double; n: integer): double;
const
  M = 50;                                   // 値を大きくするとオーバーフローします。
var
  k : integer;
  a, b, c: double;
begin
  a := 2 / pi * ln(x / 2) * Bessel(x, n, False);
  b := 0;
  for k := 0 to n - 1 do
    b := b + (factorial(n - k - 1) / factorial(k)) * power(x / 2, 2 * k - n);
  b := b / pi;
  c := 0;
  for k := 0 to M do
    c := c + power(-1, k) * (phiN(K + 1) + phiN(k + n + 1))
                         * power(x / 2, 2 * k + n) / (factorial(k) * factorial(n + k));
  c := c / pi;
  result := (a - b - c);
end;


// 第二種変形ベッセル関数a
// X 値
// n 次数
// Mnの値は積分上は∞となっていますが精度上50程度で問題ないようです。
function TForm1.KnXa(x: double; n: integer): double;
const
  MN = 50;                                  // 値を大きくするとオーバーフローします。
var
  a, b, c: double;
  p : integer;
begin
  a := power(-1, n + 1) * Bessel(x, n, true) * ln(x / 2);
  b := 0;
  for p := 0 to Mn do
    b := b + 1 / factorial(p) / factorial(n + p) * power(x / 2, 2 * p)
    * (phiN(p + 1) + phiN(p + n + 1));
  b := b * power(- 1, n) / 2 * power(x / 2, n);
  c := 0;
  for p := 0 to n - 1 do
    c := c + power(-1, p) * factorial(n - p - 1) / factorial(p) * power(x / 2, 2 * p);
  c := c / 2 * power(x / 2, -n);
  result := a + b + c;
end;


// 第二種変形ベッセル関数b
// X 値
// n 次数
// Mnの値は積分上は∞となっていますが精度上50程度で問題ないようです。
function TForm1.KnXb(x: double; n: integer): double;
const
  Mn = 50;                                  // 値を大きくするとオーバーフローします。
var
  a, b: double;
  m : integer;
begin
  a := 0;
  for m := 0 to n - 1 do
    a := a + power(-1, m) * factorial(n - m - 1) / factorial(m) * power(x / 2, 2 * m - n);
  a := a / 2;
  b := 0;
  for m := 0 to MN do
    b := b + 1 / factorial(m) / factorial(n + m) * power(x / 2, 2 * m + n)
         * (ln(x / 2) - phiN(m + 1) / 2 - phiN(n + m + 1) / 2);
  b := b * power(-1, n + 1);
  result := a + b;
end;


// 第二種ベッセル関数グラフ表示
// xmax Xの最大値
// n 次数
procedure TForm1.GraphNnX(xmax: double; n: integer);
const
  NMAX = 1000;
var
  Y, X: array of double;
  I : integer;
  XMIN: double;
begin
  setlength(Y, NMAX);
  setlength(X, NMAX);
  setlength(Y, NMAX);
  XMIN := 0.01;
  for I := 0 to NMAX - 1 do begin
    X[I] := XMIN + (xmax - XMIN) * I / NMAX;
    Y[I] := NnX(x[I], N);
  end;
  for I := 0 to NMAX - 1 do begin
    if n = 0 then Series1.AddXY(X[I], Y[I]);
    if n = 1 then Series2.AddXY(X[I], Y[I]);
    if n = 2 then Series3.AddXY(X[I], Y[I]);
  end;
end;

// 第二種ベッセル関数グラフ表示
// xmax Xの最大値
// n 次数
procedure TForm1.GraphKnX(xmax: double; n: integer);
const
  NMAX = 1000;
var
  Y, X: array of double;
  I : integer;
  XMIN: double;
begin
  setlength(Y, NMAX);
  setlength(X, NMAX);
  setlength(Y, NMAX);
  XMIN := 0.01;
  for I := 0 to NMAX - 1 do begin
    X[I] := XMIN + (xmax - XMIN) * I / NMAX;
    if Checkbox2.Checked = False then
      Y[I] := KnXa(x[I], N)
    else
      Y[I] := KnXb(x[I], N)
  end;
  for I := 0 to NMAX - 1 do begin
    if n = 0 then Series1.AddXY(X[I], Y[I]);
    if n = 1 then Series2.AddXY(X[I], Y[I]);
    if n = 2 then Series3.AddXY(X[I], Y[I]);
  end;
end;

// 第二種ベッセル関数計算
procedure TForm1.BitBtn1Click(Sender: TObject);
var
  x, Nn: double;
  ch: integer;
begin
  val(Labelededit1.Text, x, ch);
  if ch <> 0 then begin
    MessageDlg('値xに間違いがあります。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  if x <= 0 then begin
    MessageDlg('値xは0(ゼロ)以上にして下さい。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  if x > 50 then begin
    MessageDlg('値xが大きすぎます。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  Series1.Clear;
  Series2.Clear;
  Series3.Clear;
  memo1.Clear;
  if checkbox1.Checked = false then begin
    if Chart1.LeftAxis.Minimum >= 1 then begin
      Chart1.LeftAxis.Minimum := -4;
      Chart1.LeftAxis.Maximum := 1;
    end
    else begin
      Chart1.LeftAxis.Maximum := 1;
      Chart1.LeftAxis.Minimum := -4;
    end;
     GraphNnX(x, 0);
     Nn := NnX(x, 0);
     memo1.Lines.Add('N0 ' + floattostr(x) + '  ' + floattostr(Nn));
     GraphNnX(x, 1);
     Nn := NnX(x, 1);
     memo1.Lines.Add('N1 ' + floattostr(x) + '  ' + floattostr(Nn));
     GraphNnX(x, 2);
     Nn := NnX(x, 2);
     memo1.Lines.Add('N2 ' + floattostr(x) + '  ' + floattostr(Nn));
  end
  else begin
    if Chart1.LeftAxis.Minimum >= 4 then begin
      Chart1.LeftAxis.Minimum := 0;
      Chart1.LeftAxis.Maximum := 4;
    end
    else begin
      Chart1.LeftAxis.Maximum := 4;
      Chart1.LeftAxis.Minimum := 0;
    end;
    GraphKnX(x, 0);
    if Checkbox2.Checked = False then
      Nn := KnXa(x, 0)
    else
      Nn := KnXb(x, 0);
    memo1.Lines.Add('K0 ' + floattostr(x) + '  ' + floattostr(Nn));
    GraphKnX(x, 1);
    if Checkbox2.Checked = False then
      Nn := KnXa(x, 1)
    else
      Nn := KnXb(x, 1);
    memo1.Lines.Add('K1 ' + floattostr(x) + '  ' + floattostr(Nn));
    GraphKnX(x, 2);
    if Checkbox2.Checked = False then
      Nn := KnXa(x, 2)
    else
      Nn := KnXb(x, 2);
    memo1.Lines.Add('K2 ' + floattostr(x) + '  ' + floattostr(Nn));
  end;
end;

end.

  次は、次数が実数の場合のプログラムです。
計算は非整数と、整数で別の計算となります。  
非整数の計算は、簡単ですが、整数の計算は前記の様に複雑な計算となります。 第2種ベッセル関数の計算に第1種ベッセル関数を使用していますが、その計算に、次数が実数のΓ関数をが必要です。
第2種変形ベッセル関数の次数が整数の場合、Γ関数に加えて、ディガンマ関数が必要となります。
階乗!は、全てΓ関数を使用して計算しています。

 Xの値が大きくなると、有効桁数不足により正しい結果が得られにくなるます。

 第1種ベッセル関数の計算精度の向上を図ったので、第2種ベッセル関数の検討もしてみました。
次数が実数の場合は、第1種ベッセル関数が使用されるのですが、第2種の整数の場合、第1種と他の計算の差分となり、第2種変形ベッセル関数では全く使用されません。
次数が実数の計算のみ精度の向上が繁栄され、整数の場合は、従来の計算の方が、精度が高くります。

 

ディガンマ関数は、参考の為に、次数が実数のディガンマ関数を使用しました。
整数のディガンマ関数でよいので、入れ替えれば、プログラムが短くなります。

// Xの値 積分計算の上限値MNによってオーバーフローを発生するので
// コンパイル設定にオーバーフローチックが必須です。
// 第二種ベッセル関数の場合次数vが整数の時と、非整数の時で、別の計算をします。

unit Main;

interface

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

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Memo1: TMemo;
    LabeledEdit1: TLabeledEdit;
    Chart1: TChart;
    Series1: TLineSeries;
    CheckBox1: TCheckBox;
    LabeledEdit2: TLabeledEdit;
    Series2: TPointSeries;
    CheckBox2: TCheckBox;
    Button1: TButton;
    CheckBox3: TCheckBox;
    procedure BitBtn1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure GraphNnX(xmax, v: double);
    procedure GraphKnX(xmax, v:double);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//-----------------------------------------------------------------------------
// Gamma_Function(x)
function Gamma_Function(z: double): double;
const
  P: array[0..7] of double =
        ( 676.5203681218851,   -1259.1392167224028,       771.32342877765313,
         -176.61502916214059,     12.507343278686905,      -0.13857109526572012,
            9.9843695780195716e-6, 1.5056327351493116e-7);
  max_double_z: double = 171.0;
var
  i : integer;
  a, t : double;
begin
  if z > max_double_z then begin
    result := maxdouble;
    exit;
  end;
  if z < 0.5 then begin
    result := pi / (sin(pi * z) * Gamma_Function(1 - Z));
    exit;
  end;
  z := z - 1;
  a := 0.99999999999980993;
  for i := 0 to length(p) - 1 do a := a + p[i] / (z + i + 1);
  t := z + length(p) - 0.5;
  result := sqrt(2 * pi) * power(t, z + 0.5) * exp(-t) * a;
end;
//*****************************************************************************

// 誤差計算用データー
const
// 第二種変形ベッセル値
// K0.5(x)
  K05x: array[0..10] of double = (infinity,
                                  0.4610685044478945584396,
                                  0.119937771968061447368,
                                  0.03602598513176459256551,
                                  0.01147762457660805343383,
                                  0.003776613374642882559528,
                                  0.001268286652381588601872,
                                  4.319659804052612483575E-4,
                                  1.486480066651728298787E-4,
                                  5.155708404839055898835E-5,
                                  1.799347809370517960812E-5
                                 );

// K0(x)
  K0x : array[0..10] of double = (infinity,
                                  0.4210244382407083333356,
                                  0.1138938727495334356527,
                                  0.03473950438627924807235,
                                  0.01115967608585302426975,
                                  0.003691098334042594274735,
                                  0.001243994328013123085233,
                                  4.247957418692318068516E-4,
                                  1.464707052228153870966E-4,
                                  5.088131295645924756974E-5,
                                  1.77800623161676518113E-5
                                  );

// 第二種ベッセル値
// Y0.5(x)
  Y05x: array[0..10] of double = (maxdouble,
                                 -0.4310988680183760795205,
                                  0.234785710406248469174,
                                  0.4560488207946331788468,
                                  0.260766076677178815403,
                                 -0.1012177091851083995651,
                                 -0.3127610759412769977597,
                                 -0.2273558238748285231269,
                                  0.04104480174033306261896,
                                  0.2423255896126850638558,
                                  0.211708866331398152919
                                 );

// Y0(x)
  Y0x : array[0..10] of double = (maxdouble,
                                   0.08825696421567695798293,
                                   0.5103756726497451195966,
                                   0.3768500100127903819671,
                                  -0.01694073932506499190364,
                                  -0.3085176252490337800736,
                                  -0.2881946839815791540691,
                                  -0.02594974396720926488428,
                                   0.2235214893875662205273,
                                   0.2499366982850246760178,
                                   0.05567116728359939142446
                                 );

//-----------------------------------------------------------------------------
// DiGamma_Function
  cutoff: double = 171.0;
  g: extended =  9.6565781537733158945718737389;
  a: array[0..8] of extended = ( +1.144005294538510956673085217e+4,
                                 -3.239880201523183350535979104e+4,
                                 +3.505145235055716665660834611e+4,
                                 -1.816413095412607026106469185e+4,
                                 +4.632329905366668184091382704e+3,
                                 -5.369767777033567805557478696e+2,
                                 +2.287544733951810076451548089e+1,
                                 -2.179257487388651155600822204e-1,
                                 +1.083148362725893688606893534e-4
                               );

  B: array[0..9] of extended = (      1.0 / (6 * 2),
                                     -1.0 / (30 * 4),
                                      1.0 / (42 * 6),
                                     -1.0 / (30 * 8),
                                      5.0 / (66 * 10),
                                   -691.0 / (2730 * 12),
                                      7.0 / (6 * 14),
                                  -3617.0 / (510 * 16),
                                  43867.0 / (796 * 18),
                                -174611.0 / (330 * 20)
                                );

  n :integer = sizeof(B) div sizeof(extended);

function xDiGamma_Asymptotic_Expansion(x: extended): extended;
var
  m, i: integer;
  term: array of extended;
  sum, xx, xj, digamma : extended;
begin
  m := n;
//  m := 3;                       // doubleの精度ではm = 3 でOk
  setlength(term, m);
  sum := 0;
  xx := x * x;
  xj := x;
  digamma := xj - 1 / (xj + xj);
  xj := xx;
  for i := 0 to  m - 1 do begin
    term[i] := B[i] / xj;
    xj := xj * xx;
  end;
  for i := m - 1 downto 0 do sum := sum + term[i];
  result := digamma - sum;
end;


function xDiGamma(x: extended): extended;
var
  lnarg, temp, term, numerator, denominator : extended;
  n, i: integer;
begin
  lnarg := (g + x - 0.5);
  numerator := 0;
  denominator := 0;
  n := sizeof(a) div sizeof(extended);
  for i := n - 1 downto 0 do begin
    temp := x + i;
    term := a[i] / temp;
    denominator := denominator + term;
    numerator := numerator + term / temp;
  end;
  denominator := denominator + 1;

  result := ln(lnarg) - (g / lnarg) - numerator / denominator;
end;

function xDiGamma_Function(x: extended): extended;
var
  sin_x, cos_x: extended;
  ix: int64;
begin
  if x > 0 then
    if x <= cutoff then begin
      if x >= 1 then result := xDiGamma(x)
                else result := xDiGamma(x + 1) - (1 / x);
      exit;
    end
    else begin
      result := xDiGamma_Asymptotic_Expansion(x);
      exit;
    end;

  if x > -MAXExtended then begin
    ix := trunc(x);
    if x = ix then begin
      result :=  MaxExtended;
      exit;
    end;
  end;
  sin_x := sin(pi * x);
  if sin_x = 0 then  begin
    result := MAXExtended;
    exit;
  end;
  cos_x := cos(pi * x);
  if abs(cos_x) = 1 then  begin
    result := MAXExtended;
    exit;
  end;

  result := xDiGamma(1 - x) - pi * cos_x / sin_x;
end;

// デイガンマファンクション
function DiGamma_Function(x: double): double;
var
  psi: extended;
begin
  psi := xDiGamma_Function(x);
  if abs(psi) < MAXDouble then begin
    result :=  psi;
    exit;
  end;
  if psi < 0 then result := -MaxDouble
             else result :=  MaxDouble;
end;

// 第一種ベッセル関数 Γ関数使用
// X 値
// v 次数
// flag false 通常 true 変形
function BesselG(X: double; v: double;  flag: boolean): double;
const
  MN = 100;
var
  M : Integer;
  B, S  : double;
begin
  S := 0;
  for M := 0 to MN do begin
    B := 1 / Gamma_Function(M + 1) / Gamma_Function(M + v + 1);   // B = 1 / (Γ(m + 1)Γ(m + n + 1))
    if not flag then
      S := S + power(-1, M) * B * power(X / 2, 2 * M + v)
    else
      S := S + B * power(X / 2, 2 * M + v)
  end;
  result := S;
end;

//----------------------- new --------------------------------------------------
// X 値
// v 次数
// flag false 通常 true 変形
function Jvx(v, x: double; flag: boolean): extended;
var
  k : integer;
  g, j, bkk: extended;

  function Bk(k : integer): extended;
  var
    kn : integer;
    Bn, Y, Zk: extended;
  begin
    Y := -(x / 2) * (x / 2);
    if flag then Y := -Y;
    Bn := 1;
    for kn := 1 to k do begin
      Zk := Y / (kn * (kn + v));
      Bn := Zk * Bn;
    end;
    result := Bn
  end;

begin
  g := Gamma_Function(1 + v);
  bkk := 0;
  for k := 0 to 100 do  bkk := bkk + Bk(k);
  j := power(x / 2, v) / g * bkk;
  result := j;
end;

// 第二種ベッセル関数
// 次数v   非整数
// 値 x
function Yax(v, x: double): double;
begin
  if Form1.CheckBox2.Checked = true then
    result := (BesselG(x, v, false) * cos(v * pi) - BesselG(x, -v, false)) / sin(v * pi)
  else
    result := (Jvx(v, x, false) * cos(v * pi) - Jvx(-v, x, false)) / sin(v * pi);
end;

// 第二種ベッセル関数
// X 値
// n 次数 整数
// Mの値は積分上は∞となっていますが精度上50程度で問題ないようです。
function Ynx(x: double; n: integer): double;
const
  M = 50;                                   // 値を大きくするとオーバーフローします。
var
  k : integer;
  a, b, c: double;
begin
  if Form1.CheckBox2.Checked = true then a := 2 / pi * ln(x / 2) * BesselG(x, n, False)
                                    else a := 2 / pi * ln(x / 2) * Jvx(n, x, False);
  b := 0;
  for k := 0 to n - 1 do
    b := b + (Gamma_Function(n - k) / Gamma_Function(k + 1)) * power(x / 2, 2 * k - n);
  b := b / pi;
  c := 0;
  for k := 0 to M do
    c := c + power(-1, k) * (DiGamma_Function(K + 1) + DiGamma_Function(k + n + 1))
                         * power(x / 2, 2 * k + n) / (Gamma_Function(k + 1) * Gamma_Function(n + k + 1));
  c := c / pi;
  result := (a - b - c);
end;

// 第二種変形ベッセル関数
// 次数v   非整数
// 値 x
function Kax(v, x: double): double;
begin
  if Form1.CheckBox2.Checked = true then
    result := pi / 2 * ((BesselG(x, -v, true) - BesselG(x, v, true)) / sin(v * pi))
  else
    result := pi / 2 * ((Jvx(-v, x, true) - Jvx(v, x, true)) / sin(v * pi));
end;

// 第二種変形ベッセル関数
// X 値
// n 次数 整数
// Mnの値は積分上は∞となっていますが精度上50程度で問題ないようです。
function KnX(x: double; n: integer): double;
const
  MN = 100;                                  // 値を大きくするとオーバーフローします。
var
  a, b, c: double;
  p : integer;
begin
  if Form1.CheckBox2.Checked = true then
    a := power(-1, n + 1) * BesselG(x, n, true) * ln(x / 2)
  else
    a := power(-1, n + 1) * Jvx(n, x, true) * ln(x / 2);
  b := 0;
  for p := 0 to Mn do
    b := b + 1 / Gamma_Function(p + 1) / Gamma_Function(n + p + 1) * power(x / 2, 2 * p)
    * (DiGamma_Function(p + 1) + DiGamma_Function(p + n + 1));
  b := b * power(- 1, n) / 2 * power(x / 2, n);
  c := 0;
  for p := 0 to n - 1 do
    c := c + power(-1, p) * Gamma_Function(n - p) / Gamma_Function(p + 1) * power(x / 2, 2 * p);
  c := c / 2 * power(x / 2, -n);
  result := a + b + c;
end;

// 第二種ベッセル関数
// v 次数
// x 値
function Yvx(v, x: double): double;
var
  n: integer;
begin
  n := round(v);
  if n = v then begin
    if n < 0 then n := abs(n);
    result := Ynx(x, n);
    if v < 0 then result := result * power(-1, n);
  end
  else result := Yax(v, x);
end;

// 第二種ベッセル関数グラフ表示
// xmax Xの最大値
// n 次数
procedure TForm1.GraphNnX(xmax, v: double);
const
  NMAX = 1000;
var
  Y, X: double;
  I  : integer;
  XMIN: double;
begin
  XMIN := 0.001;
  for I := 0 to NMAX - 1 do begin
    X := XMIN + (xmax - XMIN) * I / NMAX;
    Y := Yvx(v, X);
    if Y > 20000 then Y := 20000;
    if Y < -20000 then Y := -20000;
    Series1.AddXY(X, Y);
  end;
end;

// 第二種変形ベッセル関数
// v 次数
// x 値
function kvx(v, x: double): double;
var
  n: integer;
begin
  n := round(v);
  if n = v then begin
    if n < 0 then n := abs(n);
    result := KnX(x, n);
  end
  else result := KaX(v, x);
end;

// 第二種変形ベッセル関数グラフ表示
// xmax Xの最大値
// n 次数
procedure TForm1.GraphKnX(xmax, v: double);
const
  NMAX = 1000;
var
  Y, X: double;
  I: integer;
  XMIN: double;
begin
  XMIN := 0.001;
  for I := 0 to NMAX - 1 do begin
    X := XMIN + (xmax - XMIN) * I / NMAX;
    Y := Kvx(v, x);
    if Y > 20000 then Y := 20000;
    if Y < -20000 then Y := -20000;
    Series1.AddXY(X, Y);
  end;
end;

// 第二種ベッセル関数計算
procedure TForm1.BitBtn1Click(Sender: TObject);
var
  x, v, y: double;
  ch: integer;
begin
  val(Labelededit2.Text, v, ch);
  if ch <> 0 then begin
    MessageDlg('次数vに間違いがあります。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  val(Labelededit1.Text, x, ch);
  if ch <> 0 then begin
    MessageDlg('値xに間違いがあります。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  if x < 0 then begin
    MessageDlg('値xは0(ゼロ)以上にして下さい。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  if x > 30 then begin
    MessageDlg('値xが大きすぎます。', mtInformation, [mbOk], 0, mbOk);
    exit;
  end;
  Series1.Clear;
  Series2.Clear;
  application.ProcessMessages;
  chart1.LeftAxis.AutomaticMaximum := False;
  chart1.LeftAxis.AutomaticMinimum := False;
  if checkbox1.Checked = false then begin
    chart1.LeftAxis.Maximum := 4;
    chart1.LeftAxis.Minimum := -4;
  end
  else begin
    chart1.LeftAxis.Maximum := 10;
    chart1.LeftAxis.Minimum := -1;
  end;

  memo1.Clear;
  y := 0;
  if checkbox1.Checked = false then begin
    if x > 0 then begin
      y := Yvx(v, x);
      if Chart1.LeftAxis.Minimum >= y + 4 then begin
        Chart1.LeftAxis.Minimum := y - 4;
        Chart1.LeftAxis.Maximum := y + 4;
      end
      else begin
        Chart1.LeftAxis.Maximum := y + 4;
        Chart1.LeftAxis.Minimum := y - 4;
      end;
      GraphNnX(10, v);
      memo1.Lines.Add('第二種ベッセル関数値');
      memo1.Lines.Add('Yv(x) = ' + floatTostr(y));
    end;
  end
  else begin
    if x > 0 then begin
      y := Kvx(v, x);
      if Chart1.LeftAxis.Minimum >= y + 4 then begin
        Chart1.LeftAxis.Minimum := y - 1;
        Chart1.LeftAxis.Maximum := y + 4;
      end
      else begin
        Chart1.LeftAxis.Maximum := y + 4;
        Chart1.LeftAxis.Minimum := y - 1;
      end;
      GraphKnX(10, v);
      memo1.Lines.Add('第二種変形ベッセル関数値');
      memo1.Lines.Add('Kv(x) = ' + floatTostr(y));
    end;
  end;
  if (x > 0) then Series2.AddXY(x, y);
//  if (x > 0) and (abs(y) < 9996) then Series2.AddXY(x, y);
  if x = 0 then begin
    if checkbox1.Checked = false then begin
      memo1.Lines.Add('第二種ベッセル関数値');
      if v > 0 then
        memo1.Lines.Add('Yv(x) = - ∞')
      else
        memo1.Lines.Add('Yv(x) = ∞');
    end
    else begin
      memo1.Lines.Add('第二種変形ベッセル関数値');
      memo1.Lines.Add('Kv(x) = ∞');
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i, p, l: integer;
  yk: extended;
  def : extended;
  defs, re, ex, ads, no : string;
begin
  memo1.Clear;
  Series1.Clear;
  Series2.Clear;
  chart1.LeftAxis.AutomaticMaximum := true;
  chart1.LeftAxis.AutomaticMinimum := False;
  chart1.LeftAxis.Minimum := 0;
  {$IFDEF CPUX64}
  chart1.LeftAxis.Title.Caption := 'xxE16';
  Memo1.Lines.Append('X64 double');
  {$ELSE}
  chart1.LeftAxis.Title.Caption := 'xxE16';
  Memo1.Lines.Append('X86');
  {$ENDIF}

  if checkbox3.Checked = true then begin
    if checkbox1.Checked = true then
      memo1.Lines.Add('K0.5(x)誤差')
    else
      memo1.Lines.Add('Y0.5(x)誤差');
  end
  else begin
    if checkbox1.Checked = true then
      memo1.Lines.Add('K0(x)誤差')
    else
      memo1.Lines.Add('Y0(x)誤差');
  end;
  for i := 0 to 10 do begin
    if i <> 0 then begin
      if checkbox3.Checked = true then begin
        if checkbox1.Checked = true then begin
          yk := Kvx(1 / 2, i);
          def := abs(K05x[i] - yk);
        end
        else begin
          yk := Yvx(1 / 2, i);
          def := abs(Y05x[i] - yk);
        end;
      end
      else  begin
        if checkbox1.Checked = true then begin
          yk := Kvx(0, i);
          def := abs(K0x[i] - yk);
        end
        else begin
          yk := Yvx(0, i);
          def := abs(Y0x[i] - yk);
        end;
      end;
    end
    else def := 0;
    {$IFDEF CPUX64}
    Series1.AddXY(i, def * 1E16);
    {$ELSE}
    Series1.AddXY(i, def * 1E16);
    {$ENDIF}
    if def <> 0 then
      defs := floatTostr(def)
    else defs := '      0';

    l := length(defs);
    p := pos('E', defs, 1);
    re := copy(defs, 0, 4);
    ex := copy(defs, p, l - p + 1);
    no := inttostr(i);
    if i < 10 then no := '  ' + no;
    if i mod 2 = 0 then  begin
      ads := no + '  ' + re + ex;
      if i = 10 then memo1.Lines.Text := memo1.Lines.Text + ads;
    end
    else begin
      ads := ads + '      ' + no + '  ' + re + ex;
      memo1.Lines.Append(ads);
    end;
  end;
end;

end.

 

複素数演算のプログラム

 複素数でベッセル関数の計算をする為には、Delphi標準のVariantによる複素数では、有効桁数が不足するので、多倍長演算を使用します。

 多倍長の組み込みは  MPArithからmparith_2018-11-27.zipをダウンロードして下さい。
Zipファイルを解凍して、解凍したフォルダーにパス(ツール->オプション->Delphiオプション->ライブラリ->ライブラリパス)を追加し、Uses に mp_types, mp_real, mp_cmplx, mp_baseを追加すれば使用可能になります。

 また、今回はMPArithだけではなく、Rudy's Delphi CornerBigintegerを使用します。
此処には、BigDecimalもあります。
特徴として、四則演算 + - * / 等がそのまま利用できることです。
但し、三角関数や対数関数はありません。

 Rudy's Delphi Cornerを開いたら -> Free Coad -> Bigintegers for Delphi 又は BigDecimals for Delph -> 上の行の最後のリンク DelphiBigNumbers project on GitHub ->Coad▼-> Download ZIP でダウンロードします。

DelphiBigNumbers-master.zip がダウンロード出来たら、解凍したSorce フォルダーを、適当な場所にコピーして、そこへパス(ツール->オプション->Delphiオプション->ライブラリ->ライブラリパス)を追加し、usesに Velthuis.BigDecimals Velthuis.BigIntegers を追加すれば、BigDecimal Biginteger が使用可能となります。

使用方法は、解凍されたPDFファイルを参照してください。

  Bigintegerは、ベルヌーイ数の計算に使用します、ベルヌーイ数はガンマ関数の計算に必要なのですが、固定値の配列として与えるのが大変なので、プログラム内で作成します。
 Bigintegerと、mp_floatはデーター形式が違うので、テキスト形式で値の受け渡しをします。
Bigintegerは整数形式で、mp_floatの方が有効桁数が低い場合、mp_floatは、指数形式で、有効桁数に丸めて読み込むことが出来ます。
此処では、Bigintegerからmp_floatへの変換しか行いません。

* 重要
 複素数の計算にべき乗があるのですが、Delphiに用意されている VerComplexPower、 Mp_complex に用意されている、mpc_powは、そのまま使用するには問題があることがわかりました。
 説明には、a^b = exp(b*ln(a))となっているので間違いはないのですが、ab が複素数の時、Imaginary部が両方ともゼロ時で areal部がマイナスの時は答えのreal部はゼロにならなければなりませんが、意味不明な値が入ります。
もう一つの問題は、乗数 b の値に、**.5 の様に .5 の値になった時は、整数部の乗数*√の計算なのですがこの時は、realかImaginaryに意味不明な値が値が入ります。
c=a^b の複素数計算の時、ab両方の虚数部に0が発生する時は別途正しい答えがでるルーチンを作成する必要があります。

 入力値v=±100 x=±100の範囲で50桁の精度を目標にしています。
もし、精度を上げる必要がある場合は、mpf_set_default_decprec() の値を大きくして下さい。
但し、演算速度が遅くまります。


第二種ベッセル関数

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;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  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Γ

  KMV : integer;                // Σ計算最大値
  gamma : mp_float;
  pai, zero, one, two, four : mp_float;
  log_2pis2 : mp_float;

const
  KMmax = 300;                  // KM max
  Vmax  = 100;                  // v 次数 max

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

  gstr = gstr0 + gstr1;

//------------------------------------------------------------------------------

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

  GL = 8;                   // グラフ基本点数

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);                      // 1
  mpf_set_int(tmp, NB);             // tmp=NB
  while mpf_is_lt(x, tmp) do begin
    mpf_mul(v, x, v);               // v = v * x
    mpf_add(x, one, x);             // x = x + 1
  end;
  mpf_mul(x, x, tmp);               // x^2
  mpf_div(one, tmp, w);             // w = 1 / x^2
  mpf_set0(s);                      // s = 0
  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 + 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);                    // 1
  mpf_add(one, one, bi);            // bi = 2
  if n <= 1 then begin              // n <= 1  ans = 1
    goto EXT;
  end;
  for i := 2 to n do  begin         // n!
    mpf_mul(ans, bi, ans);          // ans = ans * bi
    mpf_add(bi, one, bi);           // bi + 1
  end;
EXT:
  mpf_clear(bi);
end;

//---------------------------  complex power   ---------------------------------
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);

  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_set_int(two, 2);                  // 2
    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;

  mpf_clear5(ay, ai, zero, harf, two);
end;

//-------------------------------- Jv(x) ---------------------------------------
// jv(x) 多倍長
// xcm= (x+i)値 複素数
// v 次数
// 計算精度の向上には、演算有効桁数のUPとなります。
procedure Jvx(var v : mp_float; var xcm, ri: mp_complex);
var
  k : integer;
  s, x24k, tmp, tmp0, tmp1 : mp_complex;
  xc, xs2 : mp_complex;
  kd, nd, vk : mp_float;
  khg, kf : mp_float;
  tmf, tmf0 : mp_float;
  sb : mp_complex;
begin
  mpc_init5(s, x24k, tmp, tmp0, tmp1);
  mpc_init2(xc, xs2);
  mpf_init2(khg, kf);
  mpf_init3(kd, nd, vk);
  mpf_init2(tmf, tmf0);
  mpc_init(sb);

  mpc_set0(s);                              // Σ=0
  mpc_set0(sb);                             // Σback
  mpc_set1(x24k);

  mpc_div_mpf(xcm, two, xs2);               // (x+i)/2
  mpc_mul(xs2, xs2, xc);                    // xc=((x+i)/2)^2)

  for k := 0 to KMV do begin
    mpf_set1(nd);                           // 整数数判定値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が負の整数だったら nd = 0
    end;
    if mpf_is_ne(vk, zero) and mpf_is_ne(nd, zero) then begin  // vkが負の整数の時は計算しない
      if mpf_is_ge(v, zero) then            // vが正数
        mpf_copy(PVG[k], tmf)               //   GammaMul(vk, tmf);
      else                                  // vが負数
        mpf_copy(MVG[k], tmf);              //   GammaMul(-vk, tmf);
      mpf_mul(FA[k], tmf, khg);             // k!Γ(n+k+1) vkが負の整数の時±∞
//      mpc_set_mpf(kc, kf, zero);            // kc = k + 0i  複素数
//      mpc_pow(xc, kc, x24k);                // (i(x^2)/4)^k
      mpc_div_mpf(x24k, khg, tmp0);         // ((i(x^2)/4)^k)/(k!Γ(v+k+1))
      if k mod 2 <> 0 then mpc_chs(tmp0, tmp0);     // (-1)^k
      mpc_add(s, tmp0, s);                  // Σ
      mpc_sub(s, sb, tmp0);                 // 前のΣ値との差
      if mpc_is0(tmp0) then break;          // 収束判定
      mpc_copy(s, sb);
    end;
    mpc_mul(x24k, xc, x24k);
  end;
  mpc_set_mpf(tmp, v, zero);                // v + 0i
  // x が0で次数vが負数の時power演算ゼロでの除算防止
  if mpc_is0(xs2) and mpf_is_lt(v, zero) then // v<0 xs2=0+0i 時は無限大になるので計算しない
  else begin
    mpc_powa(xs2, tmp, tmp0);                 // (x/2)^v
    mpc_mul(s, tmp0, s);                      // (x/2)^v * Σ
  end;
  mpc_copy(s, ri);

  mpc_clear5(s, x24k, tmp, tmp0, tmp1);
  mpc_clear2(xc, xs2);
  mpf_clear2(khg, kf);
  mpf_clear3(kd, nd, vk);
  mpf_clear2(tmf, tmf0);
  mpc_clear(sb);
end;

//--------------------------------- 非整数計算   -------------------------------
// 非整数 多倍長
// 第一種ベッセル関数の差分をsinで除算するため演算精度向上には大きな有効桁数が必要になります。
// 特に次数が負数側に大きく、xの値が小さい時jv(x)の値が非常に小さくなりその差分となるので
// 大きな有効桁数が必要になります。
// xc= (x+i)
procedure ekazMul(var v : mp_float; var xc, ri: mp_complex);
var
  sv, sinvp, tmp : mp_float;
  harf, av : mp_float;
  ipPv, imPv, sipv, tmpc, xc2 : mp_complex;
begin
  mpf_init2(harf, av);
  mpf_init3(sv, sinvp, tmp);
  mpc_init5(ipPv, imPv, sipv, tmpc, xc2);

  mpc_copy(xc, xc2);

  jvx(v, xc2, ipPv);                       // J+v
  // cos90度がゼロになるように調整
  mpf_abs(v, av);                         // abs(v)
  mpf_frac(av, av);                       // avの小数部
  mpf_inv(two, harf);                     // 0.5
  mpf_sub(av, harf, av);                  // 0.5との差分
  if mpf_is0(av) then mpf_set0(tmp)       // ±90°だったら0
  else begin
    mpf_mul(v, pai, tmp);                 // vπ
    mpf_cos(tmp, tmp);                    // cos(vπ)
  end;

  mpc_mul_mpf(ipPv, tmp, ipPv);           // J+v * cos(vπ)
  mpf_chs(v, sv);                         // -v
  jvx(sv, xc2, imPv);                      // J-v
  if not mpc_is0(xc) then  begin          // xcが0でなかったら
    mpc_sub(ipPv, imPv, sipv);            // J+v * cos(vπ)- J-v
    mpf_mul(v, pai, tmp);                 // v*π
    mpf_sin(tmp, tmp);                    // sin(v*π)
    mpc_div_mpf(sipv, tmp, ri);           // (J+v * cos(vπ)- J-v)/sin(v*π)
  end;

  mpf_clear2(harf, av);
  mpf_clear3(sv, sinvp, tmp);
  mpc_clear5(ipPv, imPv, sipv, tmpc, xc2);
end;

//---------------------------整数計算-------------------------------------------
// 整数 多倍長計算
// 計算精度の向上には、演算有効桁数のUPとなります。
// z= (x+i)
procedure YnzMul(var v : mp_float; var z, ri : mp_complex);
var
  a, b, c, jnz, zc : mp_complex;
  z2, ynza, z24, mz24: mp_complex;
  tmp, tmp0, tmp1 : mp_complex;
  n : mp_float;
  mf, nnf, tmf, tmf0 : mp_float;
  tmf1, nb : mp_float;
  k, m, nn : integer;
  ab, cb : mp_complex;
begin
  if mpc_is0(z) then begin              // z = 0 の時は±∞となるので計算しない
    mpc_set0(ri);
    exit;
  end;

  mpc_init5(a, b, c, jnz, zc);
  mpc_init4(z2, ynza, z24, mz24);
  mpc_init3(tmp, tmp0, tmp1);
  mpf_init(n);
  mpf_init4(mf, nnf, tmf, tmf0);
  mpf_init2(tmf1, nb);
  mpc_init2(ab, cb);

  mpf_copy(v, nb);                          // v backup
  // 次数を正の整数として計算
  mpf_abs(v, n);                            // n = abs(v)

  nn := round(mpf_todouble(n));             // nn = 整数(n)

  mpc_div_mpf(z, two, z2);                  // (x+i)/2 -> z2
  mpc_mul(z2, z2, z24);                     // ((x+i)/2)^2

// jnz
  mpc_set0(jnz);

  Jvx(n, z, jnz);                          // Jn(z)

  mpf_div(two, pai, tmf0);                  // 2/π
  mpc_ln(z2, tmp);                          // log(z2)
  mpc_mul(tmp, jnz, tmp0);                  // Jn(z)*log(z2)
  mpc_mul_mpf(tmp0, tmf0, jnz);             // Jn(z2)log(z2)(2/π)
// jnz end

// a
  mpc_set0(a);                              // Σ=0
  mpc_set0(ab);                             // Σbackup=0
  mpc_set1(mz24);

  for m := 0 to nn -1 do begin
    mpf_div(FA[nn - m - 1], FA[m], tmf);    // (n - m - 1)! / m!
    mpf_set_int(mf, m);
    mpc_set_mpf(tmp0, mf, zero);
//    mpc_pow(z24, tmp0, tmp1);               // (((x+i)/2)^2)^m
    mpc_mul_mpf(tmp1, tmf, tmp0);           // (nn - m - 1)! / m! * (((x+i)/2)^2)^m
    mpc_add(a, tmp0, a);                    // Σ
    mpc_sub(a, ab, tmp0);
    if mpc_is0(tmp0) then break;            // 収束判定
    mpc_copy(a, ab);
    mpc_mul(mz24, z24, mz24);
  end;
  if mpf_is0(z2.im) then begin
    mpf_set_int(nnf, nn);                    // n
    mpf_abs(z2.re, tmf);
    mpf_expt(tmf, nnf, tmf0);
    if mpf_is_lt(z2.re, zero) then
      if nn mod 2 <> 0 then mpf_chs(tmf0, tmf0);
    mpc_set_mpf(tmp, tmf0, zero);
    mpc_inv(tmp, tmp);
  end
  else begin
    mpf_set_int(nnf, -nn);                    // -n
    mpc_set_mpf(tmp0, nnf, zero);             // -n+oi
    mpc_pow(z2, tmp0, tmp);                   // ((((x+i)/2)^2)^m)^(-n+0i)
  end;
  mpc_mul(a, tmp, tmp1);                    // Σ* ((((x+i)/2)^2)^m)^(-n+0i)
  mpc_div_mpf(tmp1, pai, a);                // Σ* ((((x+i)/2)^2)^m)^(-n+0i) / π
// a end

// c
  mpc_set0(c);
  mpc_set0(cb);
  mpc_set1(mz24);

  for k:= 0 to KMV do begin
    mpf_add(DG[k + 1], DG[nn + k + 1], tmf); // ψ(k+1)+ψ(n+k+1)
    mpf_mul(FA[k], FA[nn + k], tmf0);        // k!*(n+k)!
//    mpf_set_int(kf, k);
//    mpc_set_mpf(tmp, kf, zero);              // k+0i
//    mpc_pow(z24, tmp, tmp);                  // (((x+i)/2)^2)^k
    mpc_mul_mpf(tmp, tmf, tmp);              // (ψ(k+1)+ψ(n+k+1)) * (((x+i)/2)^2)^k
    mpc_div_mpf(tmp, tmf0,tmp);              // ((ψ(k+1)+ψ(n+k+1)) * (((x+i)/2)^2)^k) / (k!*(n+k)!)
    if k mod 2 <> 0 then mpc_chs(tmp, tmp);  // (-1)^k
    mpc_add(c, tmp, c);                      // Σ
    mpc_sub(c, cb, tmp);
    if mpc_is0(tmp) then break;              // 収束判定
    mpc_copy(c, cb);
    mpc_mul(mz24, z24, mz24);
  end;

  mpf_set_int(nnf, nn);
  if mpf_is0(z2.im) then begin
    mpf_abs(z2.re, tmf);
    mpf_expt(tmf, nnf, tmf0);
    if mpf_is_lt(z2.re, zero) then
      if nn mod 2 <> 0 then mpf_chs(tmf0, tmf0);
    mpc_set_mpf(tmp1, tmf0, zero);
//    mpc_inv(tmp, tmp);
  end
  else begin
    mpc_set_mpf(tmp0, nnf, zero);
    mpc_pow(z2, tmp0, tmp1);                  // ((x+i)/2)^n
  end;
  mpc_mul(c, tmp1, tmp);                    // c * ((x+i)/2)^n
  mpc_div_mpf(tmp, pai, c);                 // (c * ((x+i)/2)) / π
// c end

  mpc_sub(jnz, a, tmp);                     // jnz+a
  mpc_sub(tmp, c, ynza);                    // jnz+a+c

  mpf_div(n, two, tmf);                    // n / 2
  mpf_int(tmf, tmf0);                      // int(n / 2)
  mpf_sub(tmf, tmf0, tmf);                 // n / 2 - int(n / 2)

  // nがゼロ以下で奇数だったら 次数が整数でマイナスの時の処理 奇数だとtmf=0.5
  if mpf_is_lt(nb, zero) and  mpf_is_ne(tmf, zero) then  // (-1)^n
    mpc_chs(ynza, ri)                      // 奇数時
  else
    mpc_copy(ynza, ri);                    // 偶数時

  mpc_clear5(a, b, c, jnz, zc);
  mpc_clear4(z2, ynza, z24, mz24);
  mpc_clear3(tmp, tmp0, tmp1);
  mpf_clear(n);
  mpf_clear4(mf, nnf, tmf, tmf0);
  mpf_clear2(tmf1, nb);
  mpc_clear2(ab, cb);
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);

  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 TForm1.chart1coment;
begin
  Chart1.Canvas.Font.Size := 8;
  Chart1.Canvas.Font.Style := [];
  chart1.Canvas.Font.Color := clred;
  chart1.Canvas.TextOut(chart1.Width - 30, 1,'実数');
  chart1.Canvas.Font.Color := clblue;
  chart1.Canvas.TextOut(chart1.Width - 30, 13,'虚数');
  chart1.Canvas.Pen.Width := 1;
  chart1.Canvas.Pen.Color := clred;
  chart1.Canvas.MoveTo(chart1.Width - 50, 6);
  chart1.Canvas.LineTo(chart1.Width - 32, 6);
  chart1.Canvas.Pen.Color := clblue;
  chart1.Canvas.MoveTo(chart1.Width - 50, 18);
  chart1.Canvas.LineTo(chart1.Width - 32, 18);
end;

//------------------------------------------------------------------------------
// ta[] グラフ用計算点配列
procedure TForm1.Button1Click(Sender: TObject);
label
  EXT;
const
//  ta : array[0..GL - 1] of double = (0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4);
  ta : array[0..GL - 1] of double = (0.08, 0.16, 0.32, 0.64, 1.2, 2, 3, 4);
  YPM = 1E304;              // double の最大値制限 オーバーフロー対策
  YMM = - YPM;
var
  ch, i, xi: integer;
  kerx, keix: double;
  kerxe, keixe: double;
  x, v, xv, ia : double;
  xmin, xmax, dx, dxf: double;
  ymin, ymax: double;

  xm, vm, ndm, dxm: mp_float;
  avm, andm: mp_float;
  tmp, nd : mp_float;
  xc, epc, ri, tmc : mp_complex;
  berl : Darray;
  beil : Darray;
  beru : Darray;
  beiu : Darray;
  xl   : Darray;
  xu   : Darray;
  vmaxmes : string;
  GCF : integer;
  StopWatch : TStopwatch;
  ElapsedMillseconds : Int64;
  mm, ss, ms : integer;
  k : integer;
  vk, tmf, tmf0, iam : mp_float;

  GU, GS : integer;
  // xの値を複素数に変換
  procedure xtoxc(var x, ia : mp_float; var xc : mp_complex);
  begin
    mpc_set_mpf(xc, x, ia);                 // xc
  end;
  // doubleの最大値の制限
  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, v, ch);
  if ch <> 0 then begin
    application.MessageBox('次数vの値に間違いがあります。','注意', 0);
    exit;
  end;
  if v > vmax then begin
    vmaxmes := 'Vの値は ' + intTostr(vmax) + '以下にして下さい。';
    application.MessageBox(pwideChar(vmaxmes),'注意', 0);
    exit;
  end;
{  if V < -31 then begin     // マイナス側を広げるには得演算の有効桁数を増やす必要があります。
    vmaxmes := 'Vの値は -31 より大きしてください。';
    application.MessageBox(pwideChar(vmaxmes),'注意', 0);
    exit;
  end; }
  val(labelededit2.Text, x, ch);
  if ch <> 0 then begin
    application.MessageBox('xの値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(x) > 100 then begin
    vmaxmes := 'xの値は±100迄にしてください';
    application.MessageBox(pchar(vmaxmes),'注意', 0);
    exit;
  end;
  if (v < 0) and (x <> 0) then
    if abs(x) < 1E-10 then begin
      vmaxmes := 'vが負数の時はxの絶対値は1E-10より大きしてください。';
      application.MessageBox(pwideChar(vmaxmes),'注意', 0);
      exit;
    end;
  val(labelededit3.Text, ia, ch);
  if ch <> 0 then begin
    application.MessageBox('i の値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(ia) > 100 then begin
    vmaxmes := 'i の値は±100迄にしてください';
    application.MessageBox(pchar(vmaxmes),'注意', 0);
    exit;
  end;

//  KMV := 50 + round((abs(x) + abs(ia)) * 10);
//  if KMV > KMmax then  KMV := KMmax;              // Σ 0~kMAX
  kmv := KMmax;
  mpf_init4(vm, xm, ndm, dxm);
  mpf_init2(avm, andm);
  mpf_init2(tmp, nd);
  mpf_init4(vk, tmf, tmf0, iam);
  mpc_init4(xc, epc, ri, tmc);

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

  memo1.Clear;

  mpf_int(vm, ndm);
  mpf_sub(vm, ndm, ndm);                     // 整数ならndm = 0
  mpf_abs(ndm, andm);                        // 小数部の値

  mpf_read_decimal(dxm, PAnsiChar(ansistring('1E-10' + #00)));

  if mpf_is_lt(andm, dxm) and mpf_is_ne(ndm, zero) then begin
    application.MessageBox('次数vの値の小数部は 1E-10 より大きくしてください。','注意', 0);
    goto EXT;
  end;

  // Γ値配列計算
  mpf_abs(vm, avm);                         // +v
  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                                                      // vkが負の整数
      mpf_set0(MVG[k]);                     // Γ(n+k+1) = 0
  end;


  if ia >= 0 then vmaxmes := ' +' + floatTostr(ia) + 'i'
             else vmaxmes := ' ' + floatTostr(ia) + 'i';
  memo1.Lines.Append('v = ' + floatTostr(v) + '  x = ' + floatTostr(x) + vmaxmes);


  StopWatch := TStopwatch.StartNew;

  // 表示値の計算
  mpf_abs(vm, avm);
  xToxc(xm, iam, xc);

  // xc <> 0 の時の表示設定
  if not mpc_is0(xc) then begin                            // xc <> 0
    if mpf_is_ne(ndm, zero) then
      ekazMul(vm, xc, ri)
    else
      ynzMul(vm, xc, ri);

    memo1.Lines.Append('Yv(x) = ' +  string(mpf_decimal(ri.re, 50)));
    // i部表示
    if mpf_is_ge(ri.im, zero) then                                    // im>=0    表示iに+符号追加
      memo1.Lines.Append('          +' +  string(mpf_decimal(ri.im, 50)) + ' i')
    else                                                              // im<0     表示i
      memo1.Lines.Append('          ' +  string(mpf_decimal(ri.im, 50)) + ' i');
    kerxe := mpf_todouble(ri.re);
    keixe := mpf_todouble(ri.im);
  end
  // xc = 0 の時の表示値設定
  else begin                                              // xc = 0
    // v >= 0
    if mpf_is_ge(vm, zero) then begin
      memo1.Lines.Append('Yv(x) = -INF');                 // 実数部 -∞
      memo1.Lines.Append('        = +0i');                // 虚数部 0i
      kerxe := -infinity;
      keixe := 0;
    end
    // v <  0
    else begin
      mpf_int(avm, tmp);                                  // avmの整数部
      mpf_sub(avm, tmp, tmf0);                            // avmの小数部
      mpf_div(one, two, tmf);                             // 0.5
      // avmの小数部が0.5
      if mpf_is_eq(tmf, tmf0) then begin
        memo1.Lines.Append('Yv(x) =  0');                 // 実数部  0
        memo1.Lines.Append('        = +0i');              // 虚数部 0i
        kerxe := 0;
        keixe := 0;
      end
      // avmの小数部が0.5でなかったら0.5加算します
      else begin
        mpf_add(avm, tmf, tmp);                           // avm + 0.5
        mpf_int(tmp, tmf0);                               // avm + 0.5 -> 整数
        mpf_div(tmf0, two, tmf0);                         // 整数/2
        mpf_frac(tmf0, tmf0);                             // 小数部取り出し
        // avm+0.5が偶数だったら
        if mpf_is0(tmf0) then begin
          memo1.Lines.Append('Yv(x) = -INF');             // 実数部 -∞
          kerxe := -infinity;
        end
        // amv+0.5が奇数だったら
        else begin
          memo1.Lines.Append('Yv(x) = INF');              // 実数部 +∞
          kerxe := infinity;
        end;
        memo1.Lines.Append('        = +0i');              // 虚数部 0i
        keixe := 0;
      end;
    end;
  end;

  StopWatch.Stop;
  ElapsedMillseconds := StopWatch.ElapsedMilliseconds;

//  goto EXT;

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

  series1.Clear;
  series2.Clear;
  series3.Clear;
  series4.Clear;
  series5.Clear;
  series6.Clear;

  application.ProcessMessages;

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

  if ElapsedMillseconds > 500 then begin
    vmaxmes := vmaxmes + #13#10 + 'グラフの表示をしますか?';
    if MessageDlg(vmaxmes , mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrNo then begin
      Chart1.Canvas.Font.Style := [fsBold];
      Chart1.Canvas.Font.size := 8;
      Chart1.Canvas.TextOut(170, 115,'グラフ無し');
      goto EXT;
    end;
  end;

  // 最大値最小値の検索とグラフデーター作成
  xi := round(x);
  xmin := xi - 4;
  GCF := 0;
  if (x >= -2) and (x <=  2) then GCF := 1;
  if (x >= -3) and (x <= -2) then GCF := 2;
  if (x >=  2) and (x <=  3) then GCF := 3;
  if (x >= -4) and (x <= -3) then GCF := 4;
  if (x >=  3) and (x <=  4) then Gcf := 5;
  case GCF of
    0:  xmin := xi - 4;
    1:  xmin := -4;
    2:  xmin := -5;
    3:  xmin := -3;
    4:  xmin := -6;
    5:  xmin := -2;
  end;
  xmax := xmin + 8;
  case GCF of
    0 : begin
          setlength(berl, GL + GL);
          setlength(beil, GL + GL);
          setlength(xt, GL + GL); setlength(yt, GL + GL);
          setlength(xl, GL + GL);
        end;
    1, 2, 3, 4, 5:
        begin
          setlength(berl, GL); setlength(beru, GL);
          setlength(beil, GL); setlength(beiu, GL);
          setlength(xt, GL); setlength(yt, GL);
          setlength(xl, GL); setlength(xu, GL);
        end;
  end;

  dxf := 0.1;
  dx  := dxf;

  GS := 40;
  GU := 40;
  ch := GCF;
  case GCF of
    0 :
      begin
        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;
      end;
    1 :
      begin
        for i := 0 to GL - 1 do begin
          xu[i] := ta[i];
          xl[GL - i - 1] := -ta[i];
        end;
      end;
    else              // 2,3,4,5
      begin
        for i := 0 to GL - 1 do begin
          xu[i] := ta[i];
          xl[GL - i - 1] := -ta[i];
        end;
        case ch of
          2 : begin dx  := 5 / 4; dxf := 3 / 4; GS := 50; GU := 30; end;
          3 : begin dx  := 3 / 4; dxf := 5 / 4; GS := 30; GU := 50; end;
          4 : begin dx  := 6 / 4; dxf := 2 / 4; GS := 60; GU := 20; end;
          5 : begin dx  := 2 / 4; dxf := 6 / 4; GS := 20; GU := 60; end;
        end;
        for i := 0 to Gl - 1 do begin
          xl[i] := xl[i] * dx;
          xu[i] := xu[i] * dxf;
        end;
      end;
  end;

  // グラフ用データー作成
  ymin := 0;
  ymax := 0;
  case GCF of
    0 : begin
      for i := 0 to GL + GL - 1 do begin
        xv := xl[i];
        mpf_set_dbl(tmp, xv);
        xToxc(tmp, iam, xc);
        if mpf_is_ne(ndm, zero) then
          ekazMul(vm, xc, ri)
        else
          ynzMul(vm, xc, ri);

        berl[i] := maxmin(mpf_todouble(ri.re));
        beil[i] := maxmin(mpf_todouble(ri.im));
        if berl[i] > ymax then ymax := berl[i];
        if beil[i] > ymax then ymax := beil[i];
        if berl[i] < ymin then ymin := berl[i];
        if beil[i] < ymin then ymin := beil[i];
      end;
    end;
    1, 2, 3, 4, 5:
      for i := 0 to GL - 1 do begin
        xv := xl[i];
        mpf_set_dbl(tmp, xv);
        xToxc(tmp, iam, xc);
        if mpf_is_ne(ndm, zero) then
          ekazMul(vm, xc, ri)
        else
          ynzMul(vm, xc, ri);

        berl[i] := maxmin(mpf_todouble(ri.re));
        beil[i] := maxmin(mpf_todouble(ri.im));
        if berl[i] > ymax then ymax := berl[i];
        if beil[i] > ymax then ymax := beil[i];
        if berl[i] < ymin then ymin := berl[i];
        if beil[i] < ymin then ymin := beil[i];

        xv := xu[i];
        mpf_set_dbl(tmp, xv);
        xToxc(tmp, iam, xc);
        if mpf_is_ne(ndm, zero) then
          ekazMul(vm, xc, ri)
        else
          ynzMul(vm, xc, ri);

        beru[i] := maxmin(mpf_todouble(ri.re));
        beiu[i] := maxmin(mpf_todouble(ri.im));
        if beru[i] > ymax then ymax := beru[i];
        if beiu[i] > ymax then ymax := beiu[i];
        if beru[i] < ymin then ymin := beru[i];
        if beiu[i] < ymin then ymin := beiu[i];
      end;
  end;

  if abs(ymin) < 0.1 then ymin := -0.1;
  if ymax <  0.1 then ymax :=  0.1;


  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(x, kerxe);
  series4.AddXY(x, keixe);

  if checkbox1.Checked = true then
    case GCF of
      0:
        begin
          for  i := 0 to GL + GL - 1 do begin
            series1.AddXY(xl[i], berl[i]);
            series2.AddXY(xl[i], beil[i]);
          end;
        end;
      1, 2, 3, 4, 5 :
        begin
          for i := 0 to GL - 1 do begin
            series1.AddXY(xl[i], berl[i]);
            series2.AddXY(xl[i], beil[i]);
            series5.AddXY(xu[i], beru[i]);
            series6.AddXY(xu[i], beiu[i]);
          end;
        end;
    end;

  if checkbox1.Checked = false then
  // グラフ表示
    case GCF of
      0:
        begin
          for  i := 0 to GL + GL - 1 do begin
            xt[i] := xl[i];
            yt[i] := berl[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;
          for  i := 0 to GL + GL - 1 do yt[i] := beil[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;
      1, 2, 3, 4, 5 :
        begin
          for  i := 0 to GL- 1 do begin
            xt[i] := xl[i];
            yt[i] := berl[i];
          end;
          akima_table;
          dx := xt[0] / GS;
          for i := GS downto 1 do begin
            xv := dx * i;
            kerx := maxmin(akima_Interpolation(xv));
            series1.AddXY(xv, kerx);
          end;
          for  i := 0 to GL- 1 do yt[i] := beil[i];
          akima_table;
          for i := GS downto 1 do begin
            xv := dx * i;
            keix := maxmin(akima_Interpolation(xv));
            series2.AddXY(xv, keix);
          end;

          if mpf_is0(xm) then begin
//            series1.AddXY(0, kerxe);
//            series2.AddXY(0, keixe);
            series5.AddXY(0, kerxe);
            series6.AddXY(0, keixe);
          end;

          for  i := 0 to GL- 1 do begin
            xt[i] := xu[i];
            yt[i] := beru[i];
          end;
          akima_table;
          dx := xt[GL - 1] / GU;
          for i := 1 to GU do begin
            xv := dx * i;
            kerx := maxmin(akima_Interpolation(xv));
            series5.AddXY(xv, kerx);
          end;
          for  i := 0 to GL- 1 do yt[i] := beiu[i];
          akima_table;
          for i := 1 to GU do begin
            xv := dx * i;
            keix := maxmin(akima_Interpolation(xv));
            series6.AddXY(xv, keix);
          end;
        end;
    end;
  application.ProcessMessages;
  chart1coment;

EXT:
  mpf_clear4(vm, xm, ndm, dxm);
  mpf_clear2(avm, andm);
  mpf_clear2(tmp, nd);
  mpf_clear4(vk, tmf, tmf0, iam);
  mpc_clear4(xc, epc, ri, tmc);
end;

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


  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]);

  mpf_init3(N, D, tmp);
  mpf_init(gamma);
  mpf_init5(pai, zero, one, two, four);
  mpf_init(log_2pis2);

  mpf_set_pi(pai);                  // π
  mpf_set0(zero);                   // 0
  mpf_set1(one);                    // 1
  mpf_set_int(two, 2);              // 2
  mpf_set_int(four, 4);             // 4

  mpf_mul(pai, two, tmp);           // 2π
  mpf_ln(tmp, tmp);                 // ln(2π)
  mpf_div(tmp, two, log_2pis2);     // ln(2π)/2

  mpf_read_decimal(gamma, PAnsiChar(ansistring(gstr + #00)));     // γ

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

  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;

  mpf_clear3(N, D, tmp);
end;

procedure TForm1.FormDestroy(Sender: TObject);
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 GL + GL - 1 do mpf_clear(t[i]);
  for i := 0 to GL + GL + 2 do mpf_clear(m[i]);
  for i := 0 to KMmax do mpf_clear(PVG[i]);
  for i := 0 to KMmax do mpf_clear(MVG[i]);
  mpf_clear(gamma);
  mpf_clear5(pai, zero, one, two, four);
  mpf_clear(log_2pis2);
end;

end.

 

第二種変形ベッセル関数

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;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  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Γ

  KMV : integer;                // Σ計算最大値
  gamma : mp_float;
  pai, zero, one, two, four : mp_float;
  log_2pis2 : mp_float;

const
  KMmax = 250;                  // KM max
  Vmax  = 100;                  // v 次数 max

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

  gstr = gstr0 + gstr1;

//------------------------------------------------------------------------------

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

  GL = 8;             // グラフ基本点数

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);                      // 1
  mpf_set_int(tmp, NB);             // tmp=NB
  while mpf_is_lt(x, tmp) do begin
    mpf_mul(v, x, v);               // v = v * x
    mpf_add(x, one, x);             // x = x + 1
  end;
  mpf_mul(x, x, tmp);               // x^2
  mpf_div(one, tmp, w);             // w = 1 / x^2
  mpf_set0(s);                      // s = 0
  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 + 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);                    // 1
  mpf_add(one, one, bi);            // bi = 2
  if n <= 1 then begin              // n <= 1  ans = 1
    goto EXT;
  end;
  for i := 2 to n do  begin         // n!
    mpf_mul(ans, bi, ans);          // ans = ans * bi
    mpf_add(bi, one, bi);           // bi + 1
  end;
EXT:
  mpf_clear(bi);
end;

//--------------------------------- 非整数計算   -------------------------------
var
  rk, ik : double;                          // x=0 で、無限大時の値

//------------------- complex power --------------------------------------------
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);

  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_set_int(two, 2);                  // 2
    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);
  end;

  mpf_clear5(ay, ai, zero, harf, two);
end;

// 第一種変形ベッセル関数
// 非整数多倍長で計算
// xs2 = x / 2
procedure sigumaaIaxMul(var v : mp_float; var xs2, ri : mp_complex);
var
  k : integer;
  khg :  mp_float;
  s, x24k, tmp, tmp0, xei: mp_complex;
  sb, xei2 : mp_complex;
  tmf0 : mp_float;
begin
  mpc_init5(s, x24k, tmp, tmp0, xei);
  mpc_init2(sb, xei2);
  mpf_init(khg);
  mpf_init(tmf0);

  mpc_set0(s);                              // Σ=0
  mpc_set0(sb);                              // Σ=0
  mpc_copy(xs2, xei);
  mpc_mul(xei, xei, xei2);                 // xei^2
  mpc_set1(x24k);

  for k := 0 to KMV do begin
    if mpf_is_ge(v, zero) then
      mpf_copy(PVG[k], tmf0)              // v > 0 Γ(v+k+1)
    else
      mpf_copy(MVG[k], tmf0);             // v <=0    Γ(v+k+1)
    mpf_mul(FA[k], tmf0, khg);            // k!Γ(n+k+1)
//    mpf_set_int(tmf, K + K);              // 2k
//    mpc_set_mpf(kc, tmf, zero);           // kc = 2k + 0i  複素数
//    mpc_powa(xei, kc, x24k);               // (i(x^2)/4)^k
    mpc_div_mpf(x24k, khg, tmp0);         // ((i(x^2)/4)^k)/(k!Γ(v+k+1)) vkが0,負の整数の時±∞
    mpc_add(s, tmp0, s);                  // Σ
    mpc_sub(s, sb, tmp0);
    if mpc_is0(tmp0) then break;
    mpc_copy(s, sb);
    mpc_mul(x24k, xei2, x24k);
  end;
  if mpf_is_ge(v, zero) or not mpc_is0(xei) then begin  // v がゼロより大きいか xがゼロでない時
    mpc_set_mpf(tmp, v, zero);              // v + 0i
    mpc_powa(xei, tmp, tmp0);                // ((xe^(iπ/4)) /2)^V
    mpc_mul(s, tmp0, s);                    // Σ
  end;

  mpc_copy(s, ri);

  mpc_clear5(s, x24k, tmp, tmp0, xei);
  mpc_clear2(sb, xei2);
  mpf_clear(khg);
  mpf_clear(tmf0);
end;

// 非整数 多倍長
// 第一種変形ベッセル関数の差分をsinで除算するため演算精度向上には大きな有効桁数が必要になります。
procedure ekazMul(var v : mp_float; var x, ri: mp_complex);
var
  sv, sinvp, tmp : mp_float;
  ipPv, imPv, sipv, tmpc : mp_complex;
begin
  mpf_init3(sv, sinvp, tmp);
  mpc_init4(ipPv, imPv, sipv, tmpc);

  sigumaaIaxMul(v, x, ipPv);                    // ipv
  mpf_chs(v, sv);
  sigumaaIaxMul(sv, x, imPv);                   // imv
  if not mpc_is0(x) then  begin
    mpc_sub(imPv, ipPv, sipv);                  // imv - ipv
    mpf_mul(v, pai, tmp);                       // v * π
    mpf_sin(tmp, tmp);                          // sin(v * pi)
    mpc_div_mpf(sipv, tmp, sipv);               // (imv - ipv)/sin(v * pi)
    mpf_div(pai, two, tmp);                     // π /2
    mpc_mul_mpf(sipv, tmp, ri);                 // (Imv - Ipv) / sin(v * pi) * pi / 2
  end;

  mpf_clear3(sv, sinvp, tmp);
  mpc_clear4(ipPv, imPv, sipv, tmpc);
end;

//---------------------------整数計算-------------------------------------------
// 整数 多倍長計算
// 計算精度の向上には、Σの最大値のUPと演算有効桁数のUPとなります。
procedure knzMul(var v : mp_float; var z, ri : mp_complex);
var
  a, b, c, inz, zc : mp_complex;
  z2, knza, z24, mz24: mp_complex;
  tmp, tmp0, tmp1 : mp_complex;
  n, mone : mp_float;
  mf, nnf, tmf, tmf0 : mp_float;
  tmf1, nb : mp_float;
  k, m, nn : integer;
  inzb, ab, cb : mp_complex;
begin
  if mpc_is0(z) then begin              // z = 0 の時は±∞となるので計算しない
    mpc_set0(ri);
    exit;
  end;

  mpc_init5(a, b, c, inz, zc);
  mpc_init4(z2, knza, z24, mz24);
  mpc_init3(tmp, tmp0, tmp1);
  mpf_init2(n, mone);
  mpf_init4(mf, nnf, tmf, tmf0);
  mpf_init2(tmf1, nb);
  mpc_init3(inzb, ab, cb);

  mpf_copy(v, nb);
  mpf_abs(v, n);

  nn := abs(round(mpf_todouble(n)));
  mpf_chs(one, mone);

  mpc_copy(z, z2);                            // z -> z2
  mpc_mul(z2, z2, z24);                       // (z/2)^2
//  mpc_chs(z24, mz24);                         // -(z/2)^2

//  form1.memo1.Lines.Append('z/2 =' + string(mpf_decimal_alt(z24.im, 50)));

  mpc_set0(inz);
  mpc_set0(inzb);
  mpc_set1(mz24);

// Inz
  for m := 0 to KMV do begin
    mpf_mul(FA[m], FA[m + nn], tmf);
    mpf_set_int(mf, m);
    mpc_set_mpf(tmp0, mf, zero);
//    mpc_pow(z24, tmp0, tmp1);
    mpc_div_mpf(tmp1, tmf, tmp0);
    mpc_add(inz, tmp0, inz);
    mpc_sub(inz, inzb, tmp0);
    if mpc_is0(tmp0) then break;
    mpc_copy(inz, inzb);
    mpc_mul(mz24, z24, mz24);
  end;
//  form1.memo1.Lines.Append('lnz = ' + string(mpf_decimal_alt(inz.im, 50)));

  mpf_set_int(nnf, nn);
  mpc_set_mpf(tmp0, nnf, zero);
  mpc_pow(z2, tmp0, tmp);
  mpc_mul(inz, tmp, inz);
//  form1.memo1.Lines.Append( string(mpf_decimal_alt(inz.im, 50)));

// a
  mpc_set0(a);
  mpc_set0(ab);
  mpc_set1(mz24);

  for k := 0 to nn - 1 do begin
    mpf_div(FA[nn - k - 1], FA[k], tmf);
    mpc_set_mpf(tmp0, tmf, zero);
//    mpf_set_int(kf, k);
//    mpc_set_mpf(tmp1, kf, zero);
//    mpc_pow(z24, tmp1, tmp1);
    mpc_mul(tmp0, tmp1, tmp);
    if k mod 2 <> 0 then mpc_chs(tmp, tmp);
    mpc_add(a, tmp, a);
    mpc_sub(a, ab, tmp);
    if mpc_is0(tmp) then break;
    mpc_copy(a, ab);
    mpc_mul(mz24, z24, mz24);
  end;
//  form1.memo1.Lines.Append('a 1= ' + string(mpf_decimal_alt(a.im, 50)));

  mpf_set_int(nnf, -nn);
  if mpf_is0(z2.im) then begin
    mpf_abs(z2.re, tmf);
    mpf_expt(tmf, nnf, tmf);
    mpc_set_mpf(tmp, tmf, zero);
    if mpf_is_lt(z2.re, zero) then mpc_chs(tmp, tmp);
  end
  else begin
    mpc_set_mpf(tmp1, nnf, zero);
    mpc_pow(z2, tmp1, tmp);
  end;
  mpc_mul(a, tmp, tmp0);
  mpc_div_mpf(tmp0, two, a);

//  form1.memo1.Lines.Append('a2= ' + string(mpf_decimal_alt(a.im, 50)));

//  b
  if (nn + 1) mod 2 = 0 then
     mpc_set_mpf(tmp1, one, zero)
  else
     mpc_set_mpf(tmp1, mone, zero);
  mpc_ln(z2, tmp0);
  mpc_mul(tmp1, tmp0, tmp);
  mpc_mul(tmp, inz, b);

//  form1.memo1.Lines.Append( string(mpf_decimal_alt(b.re, 50)));

// c
  mpc_set0(c);
  mpc_set0(cb);
  mpc_set1(mz24);

  for k:= 0 to KMV do begin
    mpf_add(DG[k + 1], DG[nn + k + 1], tmf);
    mpf_mul(FA[k], FA[nn + k], tmf0);

//    mpf_set_int(kf, k);
//    mpc_set_mpf(tmp, kf, zero);
//    mpc_pow(z24, tmp, tmp);
    mpc_mul_mpf(tmp, tmf, tmp);
    mpc_div_mpf(tmp, tmf0,tmp);
    mpc_add(c, tmp, c);
    mpc_sub(c, cb, tmp);
    if mpc_is0(tmp) then break;
    mpc_copy(c, cb);
    mpc_mul(mz24, z24, mz24);
  end;

//  c := c * power(-1, nn) / 2 * varcomplexpower(z2, nn);

  mpf_set_int(nnf, nn);
  mpc_set_mpf(tmp0, nnf, zero);
  mpc_pow(z2, tmp0, tmp1);                  // z2^n
  mpc_mul(c, tmp1, tmp);                    // c * z2^n

  if nn mod 2 = 0 then                      // -1^nn
     mpc_set_mpf(tmp1, one, zero)
  else
     mpc_set_mpf(tmp1, mone, zero);
  mpc_div_mpf(tmp1, two, tmp0);             // (-1~n)/2
  mpc_mul(tmp, tmp0, c);                    // c :=  z2^n * c * (-1~n)/2

//  knza := a + b + c;
  mpc_add(a, b, tmp);
  mpc_add(tmp, c, knza);

  mpf_div(n, two, tmf);                    // n / 2
  mpf_int(tmf, tmf0);                      // int(n / 2)
  mpf_sub(tmf, tmf0, tmf);                 // n / 2 - int(n / 2)
// nがゼロ以下で偶数だったら
  if mpf_is_lt(nb, zero) and  mpf_is_ne(tmf, zero) then  // -1^n
    mpc_chs(knza, ri)                      // 奇数時
  else
    mpc_copy(knza, ri);                    // 偶数時

  mpc_clear5(a, b, c, inz, zc);
  mpc_clear4(z2, knza, z24, mz24);
  mpc_clear3(tmp, tmp0, tmp1);
  mpf_clear2(n, mone);
  mpf_clear4(mf, nnf, tmf, tmf0);
  mpf_clear2(tmf1, nb);
  mpc_clear3(inzb, ab, cb);
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 TForm1.chart1coment;
begin
  Chart1.Canvas.Font.Size := 8;
  Chart1.Canvas.Font.Style := [];
  chart1.Canvas.Font.Color := clred;
  chart1.Canvas.TextOut(chart1.Width - 30, 1,'実数');
  chart1.Canvas.Font.Color := clblue;
  chart1.Canvas.TextOut(chart1.Width - 30, 13,'虚数');
  chart1.Canvas.Pen.Width := 1;
  chart1.Canvas.Pen.Color := clred;
  chart1.Canvas.MoveTo(chart1.Width - 50, 6);
  chart1.Canvas.LineTo(chart1.Width - 32, 6);
  chart1.Canvas.Pen.Color := clblue;
  chart1.Canvas.MoveTo(chart1.Width - 50, 18);
  chart1.Canvas.LineTo(chart1.Width - 32, 18);
end;

//------------------------------------------------------------------------------
// ta[] グラフ用計算点配列
procedure TForm1.Button1Click(Sender: TObject);
label
  EXT;
const
  ta : array[0..GL - 1] of double = (0.08, 0.13, 0.23, 0.46, 0.86, 1.68, 2.7, 4);
  YPM = 1E304;              // double の最大値制限 オーバーフロー対策
  YMM = - YPM;
var
  ch, i, xi: integer;
  kerx, keix: double;
  kerxe, keixe: double;
  x, v, xv, ia : double;
  xmin, xmax, dx, dxf: double;
  ymin, ymax: double;

  xm, vm, ndm, dxm: mp_float;
  avm, andm: mp_float;
  tmp : mp_float;
  xc, epc, ri, tmc : mp_complex;
  berl : Darray;
  beil : Darray;
  beru : Darray;
  beiu : Darray;
  xl   : Darray;
  xu   : Darray;
  vmaxmes : string;
  GCF : integer;
  StopWatch : TStopwatch;
  ElapsedMillseconds : Int64;
  mm, ss, ms : integer;
  k : integer;
  vk, tmf, tmf0, iam : mp_float;

  GU, GS : integer;
  // xの値複素数に変換
  procedure xtoxc(var x, ia : mp_float; var xc : mp_complex);
  begin
    mpc_set_mpf(xc, x, ia);                 // xc
    mpc_div_mpf(xc, two, xc);               // xc/2
  end;
  // doubleの最大値の制限
  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, v, ch);
  if ch <> 0 then begin
    application.MessageBox('次数vの値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(v) > vmax then begin
    vmaxmes := 'Vの値は ±' + intTostr(vmax) + '以下にして下さい。';
    application.MessageBox(pwideChar(vmaxmes),'注意', 0);
    exit;
  end;
  val(labelededit2.Text, x, ch);
  if ch <> 0 then begin
    application.MessageBox('xの値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(x) > 100 then begin
    vmaxmes := 'xの値は±100迄にしてください';
    application.MessageBox(pchar(vmaxmes),'注意', 0);
    exit;
  end;
  val(labelededit2.Text, x, ch);
  if ch <> 0 then begin
    application.MessageBox('xの値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(x) > 100 then begin
    vmaxmes := 'xの値は±100迄にしてください';
    application.MessageBox(pchar(vmaxmes),'注意', 0);
    exit;
  end;
  val(labelededit3.Text, ia, ch);
  if ch <> 0 then begin
    application.MessageBox('i の値に間違いがあります。','注意', 0);
    exit;
  end;
  if abs(ia) > 100 then begin
    vmaxmes := 'i の値は±100迄にしてください';
    application.MessageBox(pchar(vmaxmes),'注意', 0);
    exit;
  end;

  KMV := KMmax;              // Σ 0~kMAX

  mpf_init4(vm, xm, ndm, dxm);
  mpf_init2(avm, andm);
  mpf_init(tmp);
  mpf_init4(vk, tmf, tmf0, iam);
  mpc_init4(xc, epc, ri, tmc);

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

  rk := 0;
  ik := 0;

  memo1.Clear;

  mpf_int(vm, ndm);
  mpf_sub(vm, ndm, ndm);                     // 整数ならndm = 0
  mpf_abs(ndm, andm);
  // Γ値配列計算
  mpf_abs(vm, avm);
  if mpf_is_ne(ndm, zero) then begin          // 次数vの値が非整数の時計算
    for k := 0 to KMV 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 KMV 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, MVG[k]);                   // Γ(n+k+1)
    end;
  end;

  mpf_read_decimal(dxm, PAnsiChar(ansistring('1E-10' + #00)));

  if mpf_is_lt(andm, dxm) and mpf_is_ne(ndm, zero) then begin
    application.MessageBox('次数vの値の小数部は 1E-10 より大きくしてください。','注意', 0);
    goto EXT;
  end;

  // ゼロ+側近辺
  mpf_read_decimal(dxm, PAnsiChar(ansistring('1E-50' + #00)));

  mpf_abs(vm, avm);
  xToxc(dxm, iam, xc);
  if mpf_is_ne(ndm, zero) then
    ekazMul(avm, xc, ri)
  else
    knzMul(avm, xc, ri);
  if mpf_is_ge(ri.re, zero) then rk := infinity
                            else rk := -infinity;
  if mpf_is_ge(ri.im, zero) then ik := infinity
                            else ik := -infinity;

  memo1.Lines.Append('v = ' + floatTostr(v) + '  x = ' + floatTostr(x));

  StopWatch := TStopwatch.StartNew;

  // 表示値の計算
  kerxe := 0;
  keixe := 0;
  // x <> 0
  xToxc(xm, iam, xc);
  if not mpc_is0(xc) then begin
    if mpf_is_ne(ndm, zero) then
      ekazMul(avm, xc, ri)
    else
      knzMul(avm, xc, ri);
{    if mpf_is0(xc.im) then begin              // mpc_pow の問題対策
      mpf_frac(avm, tmf);
      mpf_inv(two, tmf0);
      mpf_sub(tmf, tmf0, tmf);
      if mpf_is0(tmf) then
        if mpf_is_ge(xc.re,zero) then mpf_set0(ri.im)
                                 else mpf_set0(ri.re);
    end;  }
    memo1.Lines.Append('kv(x) = ' +  string(mpf_decimal(ri.re, 50)));
    if mpf_is_ge(ri.im, zero) then
      memo1.Lines.Append('       = +' +  string(mpf_decimal(ri.im, 50)) + ' i')
    else
      memo1.Lines.Append('       = ' +  string(mpf_decimal(ri.im, 50)) + ' i');
    kerxe := mpf_todouble(ri.re);
    keixe := mpf_todouble(ri.im);
  end
  // x = 0
  else begin
    memo1.Lines.Append('kv(x) = INF');
    memo1.Lines.Append('        = +0i');
    kerxe := rk;
    keixe := 0;
  end;

  StopWatch.Stop;
  ElapsedMillseconds := StopWatch.ElapsedMilliseconds;

//  goto EXT;

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

  series1.Clear;
  series2.Clear;
  series3.Clear;
  series4.Clear;
  series5.Clear;
  series6.Clear;

  application.ProcessMessages;

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

  if ElapsedMillseconds > 500 then begin
    vmaxmes := vmaxmes + #13#10 + 'グラフの表示をしますか?';
    if MessageDlg(vmaxmes , mtConfirmation, [mbYes, mbNo], 0, mbYes) = mrNo then begin
      Chart1.Canvas.Font.Style := [fsBold];
      Chart1.Canvas.Font.size := 8;
      Chart1.Canvas.TextOut(170, 115,'グラフ無し');
      goto EXT;
    end;
  end;

  // 最大値最小値の検索とグラフデーター作成
  xi := round(x);
  xmin := xi - 4;
  GCF := 0;
  if (x >= -2) and (x <=  2) then GCF := 1;
  if (x >= -3) and (x <= -2) then GCF := 2;
  if (x >=  2) and (x <=  3) then GCF := 3;
  if (x >= -4) and (x <= -3) then GCF := 4;
  if (x >=  3) and (x <=  4) then Gcf := 5;
  case GCF of
    0:  xmin := xi - 4;
    1:  xmin := -4;
    2:  xmin := -5;
    3:  xmin := -3;
    4:  xmin := -6;
    5:  xmin := -2;
  end;
  xmax := xmin + 8;
  case GCF of
    0 : begin
          setlength(berl, GL + GL);
          setlength(beil, GL + GL);
          setlength(xt, GL + GL); setlength(yt, GL + GL);
          setlength(xl, GL + GL);
        end;
    1, 2, 3, 4, 5:
        begin
          setlength(berl, GL); setlength(beru, GL);
          setlength(beil, GL); setlength(beiu, GL);
          setlength(xt, GL); setlength(yt, GL);
          setlength(xl, GL); setlength(xu, GL);
        end;
  end;

  dxf := 0.1;
  dx  := dxf;

  GS := 40;
  GU := 40;
  ch := GCF;
  case GCF of
    0 :
      begin
        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;
      end;
    1 :
      begin
        for i := 0 to GL - 1 do begin
          xu[i] := ta[i];
          xl[GL - i - 1] := -ta[i];
        end;
      end;
    else              // 2,3,4,5
      begin
        for i := 0 to GL - 1 do begin
          xu[i] := ta[i];
          xl[GL - i - 1] := -ta[i];
        end;
        case ch of
          2 : begin dx  := 5 / 4; dxf := 3 / 4; GS := 50; GU := 30; end;
          3 : begin dx  := 3 / 4; dxf := 5 / 4; GS := 30; GU := 50; end;
          4 : begin dx  := 6 / 4; dxf := 2 / 4; GS := 60; GU := 20; end;
          5 : begin dx  := 2 / 4; dxf := 6 / 4; GS := 20; GU := 60; end;
        end;
        for i := 0 to Gl - 1 do begin
          xl[i] := xl[i] * dx;
          xu[i] := xu[i] * dxf;
        end;
      end;
  end;

  // グラフ用データー作成
  ymin := 0;
  ymax := 0;
  case GCF of
    0 : begin
      for i := 0 to GL + GL - 1 do begin
        xv := xl[i];
        mpf_set_dbl(tmp, xv);
        xToxc(tmp, iam, xc);
        if mpf_is_ne(ndm, zero) then
          ekazMul(avm, xc, ri)
        else
          knzMul(avm, xc, ri);

        berl[i] := maxmin(mpf_todouble(ri.re));
        beil[i] := maxmin(mpf_todouble(ri.im));
        if berl[i] > ymax then ymax := berl[i];
        if beil[i] > ymax then ymax := beil[i];
        if berl[i] < ymin then ymin := berl[i];
        if beil[i] < ymin then ymin := beil[i];
      end;
    end;
    1, 2, 3, 4, 5:
      for i := 0 to GL - 1 do begin
        xv := xl[i];
        mpf_set_dbl(tmp, xv);
        xToxc(tmp, iam, xc);
        if mpf_is_ne(ndm, zero) then
          ekazMul(avm, xc, ri)
        else
          knzMul(avm, xc, ri);

        berl[i] := maxmin(mpf_todouble(ri.re));
        beil[i] := maxmin(mpf_todouble(ri.im));
        if berl[i] > ymax then ymax := berl[i];
        if beil[i] > ymax then ymax := beil[i];
        if berl[i] < ymin then ymin := berl[i];
        if beil[i] < ymin then ymin := beil[i];

        xv := xu[i];
        mpf_set_dbl(tmp, xv);
        xToxc(tmp, iam, xc);
        if mpf_is_ne(ndm, zero) then
          ekazMul(avm, xc, ri)
        else
          knzMul(avm, xc, ri);

        beru[i] := maxmin(mpf_todouble(ri.re));
        beiu[i] := maxmin(mpf_todouble(ri.im));
        if beru[i] > ymax then ymax := beru[i];
        if beiu[i] > ymax then ymax := beiu[i];
        if beru[i] < ymin then ymin := beru[i];
        if beiu[i] < ymin then ymin := beiu[i];
      end;
  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(x, kerxe);
  series4.AddXY(x, keixe);

  if checkbox1.Checked = true then
    case GCF of
      0:
        begin
          for  i := 0 to GL + GL - 1 do begin
            series1.AddXY(xl[i], berl[i]);
            series2.AddXY(xl[i], beil[i]);
          end;
        end;
      1, 2, 3, 4, 5 :
        begin
          for i := 0 to GL - 1 do begin
            series1.AddXY(xl[i], berl[i]);
            series2.AddXY(xl[i], beil[i]);
            series5.AddXY(xu[i], beru[i]);
            series6.AddXY(xu[i], beiu[i]);
          end;
        end;
    end;

  if checkbox1.Checked = false then
  // グラフ表示
    case GCF of
      0:
        begin
          for  i := 0 to GL + GL - 1 do begin
            xt[i] := xl[i];
            yt[i] := berl[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;
          for  i := 0 to GL + GL - 1 do yt[i] := beil[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;
      1, 2, 3, 4, 5 :
        begin
          for  i := 0 to GL- 1 do begin
            xt[i] := xl[i];
            yt[i] := berl[i];
          end;
          akima_table;
          dx := xt[0] / GS;
          for i := GS downto 1 do begin
            xv := dx * i;
            kerx := maxmin(akima_Interpolation(xv));
            series1.AddXY(xv, kerx);
          end;
          for  i := 0 to GL- 1 do yt[i] := beil[i];
          akima_table;
          for i := GS downto 1 do begin
            xv := dx * i;
            keix := maxmin(akima_Interpolation(xv));
            series2.AddXY(xv, keix);
          end;

          if mpf_is0(xm) then begin
//            series1.AddXY(0, kerxe);
//            series2.AddXY(0, keixe);
            series5.AddXY(0, kerxe);
            series6.AddXY(0, keixe);
          end;

          for  i := 0 to GL- 1 do begin
            xt[i] := xu[i];
            yt[i] := beru[i];
          end;
          akima_table;
          dx := xt[GL - 1] / GU;
          for i := 1 to GU do begin
            xv := dx * i;
            kerx := maxmin(akima_Interpolation(xv));
            series5.AddXY(xv, kerx);
          end;
          for  i := 0 to GL- 1 do yt[i] := beiu[i];
          akima_table;
          for i := 1 to GU do begin
            xv := dx * i;
            keix := maxmin(akima_Interpolation(xv));
            series6.AddXY(xv, keix);
          end;
        end;
    end;
  application.ProcessMessages;
  chart1coment;

EXT:
  mpf_clear4(vm, xm, ndm, dxm);
  mpf_clear2(avm, andm);
  mpf_clear(tmp);
  mpf_clear4(vk, tmf, tmf0, iam);
  mpc_clear4(xc, epc, ri, tmc);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i : integer;
  N, D, tmp : mp_float;
begin
  mpf_set_default_decprec(200);         // 有効桁数200桁
  setlength(BM, NB + 1);                // ベルヌーイ数 配列
  setlength(DG, KMmax + Vmax + 2);      // ディガンマ
  setlength(FA, KMmax + Vmax + 1);      // 階乗
  setlength(t, GL + GL);                // akima 補間値計算 配列 t
  setlength(m, GL + GL + 3);            // akima 補間値計算 配列 m
  setlength(PVG, KMmax + 1);     // +vΓ
  setlength(MVG, KMmax + 1);     // -vΓ


  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]);

  mpf_init3(N, D, tmp);
  mpf_init(gamma);
  mpf_init5(pai, zero, one, two, four);
  mpf_init(log_2pis2);

  mpf_set_pi(pai);                  // π
  mpf_set0(zero);                   // 0
  mpf_set1(one);                    // 1
  mpf_set_int(two, 2);              // 2
  mpf_set_int(four, 4);             // 4

  mpf_mul(pai, two, tmp);           // 2π
  mpf_ln(tmp, tmp);                 // ln(2π)
  mpf_div(tmp, two, log_2pis2);     // ln(2π)/2

  mpf_read_decimal(gamma, PAnsiChar(ansistring(gstr + #00)));     // γ

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

  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;

  mpf_clear3(N, D, tmp);
end;

procedure TForm1.FormDestroy(Sender: TObject);
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 GL + GL - 1 do mpf_clear(t[i]);
  for i := 0 to GL + GL + 2 do mpf_clear(m[i]);
  for i := 0 to KMmax do mpf_clear(PVG[i]);
  for i := 0 to KMmax do mpf_clear(MVG[i]);
  mpf_clear(gamma);
  mpf_clear5(pai, zero, one, two, four);
  mpf_clear(log_2pis2);
end;

end.

 

 

 download Bessel2_function.zip

各種プログラム計算例に戻る