2024-05-07 一般エアリー関数 追加

エアリー関数

 エアリー関数についての詳細は、ウィキペディアのエアリー関数を参照してください。
又、Airy function をwebで検索すれば沢山でてくるので、参考にしてください。

ウィキペディアではAi(z)が、で書かれているが、計算内容は、同じです。
ベッセル関数により計算されますが、:ベッセルの計算に階乗とΓ関数を使用し、級数計算の収束を行う為、グラフを作成する場合、計算に時間が掛かるので、グラフ作成はは近似計算で行います。

zの値が-2~2の間は、正規の計算で行い、それ以外の範囲は近似計算でグラフを作成します。

 プログラムの起動時に階乗とΓ配列を作成する為、お待ち画面が表示されますが、その後は表示されません。
ベッセル関数に与える次数(v)の値が1/3と固定されているのでΓ関数を先に計算しておきます。
 このプログラムでは、xの値が、-80~50となっていますが、この範囲を狭くすれば、必要な配列の大きさを小さくすることが出来るのと、演算の桁数を下げる事が出来るので計算が速くなります。
 計算結果の有効桁数50桁を保証する為、300桁の計算をしています。
大きな値の差分で、その差分が小さな値となる事があるので、計算結果の有効桁数に対して、何倍もの有効桁数が必要となります。



 プログラム

 プログラムには、二種類の多倍長計算が組み込んでありますが、組み込み方は第1種ケルビン関数v,x実数を参照して下さい。

unit Main;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    LabeledEdit2: TLabeledEdit;
    Chart1: TChart;
    Series1: TLineSeries;
    Series2: TLineSeries;
    Series3: TPointSeries;
    Series4: TPointSeries;
    CheckBox1: TCheckBox;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private 宣言 }
    procedure Setting;
  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
  BM : array of mp_float;       // ベルヌーイ数配列
  FA : array of mp_float;       // 階乗配列
  PVG : array of mp_float;      // +VΓ
  MVG : array of mp_float;      // -VΓ

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

const
  KMmax = 1000;                  // KM max   1000

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

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

// 最大公約数  ユークリッドの互除法 BigInteger
function gcd_BigInteger(x, y: BigInteger): BigInteger;
var
  t : BigInteger;
begin
  while y <> 0 do begin
    t := x mod y;
    x := y;
    y := t;
  end;
  result := x;
end;

// ベルヌーイ数
// Akiyama-Tanigawa algorithm
// BigInteger
procedure Bernoulli_number_BigInteger;
const
  n = (NB + 1) * 2;
var
  m, j, k : integer;
  a     : array of BigInteger;      // 分子
  b     : array of BigInteger;      // 分母
  tmpN  : BigInteger;               // 分子
  tmpD  : BigInteger;               // 分母
  gcd   : BigInteger;               // 最大公約数
  b0    : BigInteger;
begin
  setlength(a, n + 1);
  setlength(b, n + 1);
  k := 0;
  for m := 0 to n do begin
    a[m] := 1;                         // 分子 初期値
    b[m] := (m + 1);                                // 分母 初期値
    for j := m - 1 downto 0 do begin
      tmpN := a[j] * b[j + 1] - a[j + 1] * b[j];    // 分子
      tmpN := tmpN * (j + 1);                       // 〃
      tmpD := b[j] * b[j + 1];                      // 分母
      gcd := gcd_BigInteger(tmpN, tmpD);            // 最大公約数
      a[j] := tmpN div gcd;
      b[j] := tmpD div gcd;
    end;
    if (m > 0) and (m mod 2 = 0) then begin
      b0 := b[0];
      b0 := b0 * m * (m -1);                       // m ベルヌーイ数No
      NumeratorString[k] := a[0].tostring;
      DenominatorString[k] := b0.tostring;
      inc(k);
    end;
  end;
end;

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

// ログガンマ多倍長
procedure log_GammaMul(var x, ans : mp_float);
var
  v, w : mp_float;
  tmp, tmp0, s : mp_float;
  i : integer;
begin
  mpf_init2(v, w);
  mpf_init3(tmp, tmp0, s);

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

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

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

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

  mpf_clear3(tmp, tmp0, logG);
end;

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

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

  mpf_set1(ans);
  mpf_copy(ans, FA[0]);
  mpf_copy(ans, FA[1]);

  mpf_copy(two, bi);

  if n <= 1 then begin
    goto EXT;
  end;
  for i := 2 to n do  begin
    mpf_mul(ans, bi, ans);
    mpf_copy(ans, FA[i]);
    mpf_add(bi, one, bi);
  end;
EXT:
  mpf_clear2(bi, ans);
end;

//------------------------------------------------------------------------------
// jv(x) Iv(x) 多倍長
// X 値 実数
// v 次数
// F  false Jvx  true  Ivx
procedure Jvx(var v : mp_float; var x, ri: mp_float; F : boolean);
var
  k : integer;
  s, x24k, tmp, tmp0, tmp1 : mp_float;
  xc, xs2: mp_float;
  kd, nd, vk : mp_float;
  khg, kf : mp_float;
  tmf, tmf0 : mp_float;
  sb : mp_float;
begin
  mpf_init5(s, x24k, tmp, tmp0, tmp1);
  mpf_init2(xc, xs2);
  mpf_init2(khg, kf);
  mpf_init3(kd, nd, vk);
  mpf_init2(tmf, tmf0);
  mpf_init(sb);

  mpf_set0(s);                              // Σ=0
  mpf_set0(sb);

  mpf_div(x, two, xs2);                     // x / 2
  mpf_mul(xs2, xs2, xc);                    // (x^2)/ 4
  mpf_set1(x24k);                           // x24k = 1
  for k := 0 to KMmax do begin
    mpf_set1(nd);
    mpf_set_int(kf, k);                     // kf = k
    mpf_add(v, kf, tmf0);                   // k + v
    mpf_add(tmf0, one, vk);                 // vk = k + v + 1;
    if mpf_is_lt(vk, zero) then begin       // vk < 0 時 nxが整数か確認
      mpf_int(vk, tmf);                     // int(vk);
      mpf_sub(vk, tmf, nd);                 // vk - int(vk) vkが負の整数だったら vk = 0
    end;
    if mpf_is_ne(vk, zero) and mpf_is_ne(nd, zero) then begin  // vkが負の整数の時は計算しない
      if mpf_is_ge(v, zero) then
        mpf_copy(PVG[k], tmf)               // Γ(v+k+1) v>= 0
      else
        mpf_copy(MVG[k], tmf);              // Γ(v+k+1) v < 0
      mpf_mul(FA[k], tmf, khg);             // k!Γ(n+k+1) vkが0,負の整数の時±∞
      mpf_div(x24k, khg, tmp0);             // ((i(x^2)/4)^k)/(k!Γ(v+k+1))
      if F = false then
        if k mod 2 <> 0 then mpf_chs(tmp0, tmp0);   // (-1)^k
      mpf_add(s, tmp0, s);                  // Σ
      mpf_sub(s, sb, tmp0);
      if mpf_is0(tmp0) then break;
      mpf_copy(s, sb);
    end;
    mpf_mul(x24k, xc, x24k);                // ((x^2)/4)^k
  end;
  // x が0で次数vが負数の時power演算ゼロでの除算防止
  if mpf_is0(x) and mpf_is_lt(v, zero) then // V<0 x=0 時は無限大になるので計算しない
  else begin
    mpf_expt(xs2, v, tmp0);                 // (x/2)^v
    mpf_mul(s, tmp0, s);                    // (x/2)^v * Σ
  end;
  mpf_copy(s, ri);

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

// zの値が z < 0 の時グラフ用に近似値計算
procedure AiryS_functions(z : mp_float; var Ai, Bi : mp_float);
var
  zh3s2, pis4, zh1s4, rpi, tmp : mp_float;
  n23zppi4, sincos, az : mp_float;
begin
  mpf_init5(zh3s2, pis4, zh1s4, rpi, tmp);
  mpf_init3(n23zppi4, sincos, az);

  mpf_abs(z, az);                             // |Z|

  mpf_div(one, four, tmp);                    // 1/4
  mpf_expt(az, tmp, zh1s4);                   // z^(1/4)
  mpf_sqrt(pai, rpi);                         // √π
  mpf_div(pai, four, pis4);                   // π/4
  mpf_div(three, two, tmp);                   // 3/2
  mpf_expt(az, tmp, zh3s2);                   // z^(3/2)
  mpf_mul(zh3s2, two, tmp);                   // 2(z^(3/2))
  mpf_div(tmp, three, tmp);                   // 2/3((z^(3/2)))
  mpf_add(tmp, pis4, n23zppi4);               // 2/3((z^(3/2))) + π/4
  mpf_sin(n23zppi4, sincos);                  // sin(2/3((z^(3/2))) + π/4)
  mpf_div(sincos, rpi, tmp);                  // sin/√π
  mpf_div(tmp, zh1s4, Ai);                    // sin/√π/z^(1/4)

  mpf_cos(n23zppi4, sincos);                  // cos(2/3((z^(3/2))) + π/4)
  mpf_div(sincos, rpi, tmp);                  // cos/√π
  mpf_div(tmp, zh1s4, Bi);                    // cos/√π/z^(1/4)

  mpf_clear5(zh3s2, pis4, zh1s4, rpi, tmp);
  mpf_clear3(n23zppi4, sincos, az);
end;

// zの値が z > 0 の時グラフ用に近似値計算
procedure AiryL_functions(z : mp_float; var Ai, Bi : mp_float);
var
  zh3s2, zh1s4, ehmzh3s2, tmp : mp_float;
  rpi, n2s3z3s2: mp_float;
begin
  mpf_init4(zh3s2, zh1s4, ehmzh3s2, tmp);
  mpf_init2(rpi, n2s3z3s2);

  mpf_div(three, two, tmp);               // 3/2
  mpf_expt(z, tmp, zh3s2);                // z^(3/2)
  mpf_mul(zh3s2, two, tmp);               // 2z^(3/2)
  mpf_div(tmp, three, n2s3z3s2);          // (2/3)z^(3/2)
  mpf_chs(n2s3z3s2, tmp);                 // -(2/3)z^(3/2)
  mpf_exp(tmp, ehmzh3s2);                 // e^(-(2/3)z^(3/2))
  mpf_div(one, four, tmp);                // 1/4
  mpf_expt(z, tmp, zh1s4);                // z^(1/4)
  mpf_sqrt(pai, rpi);                     // √π
  mpf_div(ehmzh3s2, two, tmp);            // (e^(-(2/3)z^(3/2)))/2
  mpf_div(tmp, rpi, tmp);                 // (e^(-(2/3)z^(3/2)))/2/√π
  mpf_div(tmp, zh1s4, Ai);                // Ai = (e^(-(2/3)z^(3/2)))/2/√π/z^(1/4)

  mpf_exp(n2s3z3s2, ehmzh3s2);            // e^((2/3)z^(3/2))
  mpf_div(ehmzh3s2, rpi, tmp);            // (e^((2/3)z^(3/2)))/√π
  mpf_div(tmp, zh1s4, Bi);                // Bi = (e^((2/3)z^(3/2)))/√π/z^(1/4)

  mpf_clear4(zh3s2, zh1s4, ehmzh3s2, tmp);
  mpf_clear2(rpi, n2s3z3s2);
end;

// Airy関数 多倍長
procedure Airy_functions(z : mp_float; var Ai, Bi : mp_float);
var
  pv, mv, az: mp_float;
  z32, s23, rz, r3, s32 : mp_float;
  sz32, Ipv, Imv, Jpv, Jmv : mp_float;
  g23, s16, p323, p316 : mp_float;
begin
  mpf_init3(pv, mv, az);
  mpf_init5(z32, s23, rz, r3, s32);
  mpf_init5(sz32, Ipv, Imv, Jpv, Jmv);
  mpf_init4(g23, s16, p323, p316);
  mpf_div(one, three, pv);          // +v = 1/3
  mpf_chs(pv, mv);                  // -v = -1/3
  mpf_div(two, three, s23);         // 2/3
  mpf_div(pv, two, s16);            // 1/6 = 1/3/2
  mpf_div(three, two, s32);         // 3/2
  mpf_abs(z, az);                   // |z|
  if mpf_is0(z) then begin
    mpf_expt(three, s23, p323);     // 3^(2/3)
    gammaMul(s23, g23);             // Γ(2/3)
    mpf_div(one, p323, Ai);         // 1/3^(2/3)
    mpf_div(Ai, g23, Ai);           // Ai=1/3^(2/3)/Γ(2/3)
    mpf_expt(three, s16, p316);     // 3^(1/6)
    mpf_div(one, p316, Bi);         // 1/3^(1/6)
    mpf_div(Bi, g23, Bi);           // Bi=1/3^(1/6)/Γ(2/3);
  end
  else begin
    mpf_expt(az, s32, z32);          // z^(3/2)
    mpf_mul(z32, s23, sz32);        // (2/3)Z^(3/2)
    mpf_sqrt(az, rz);               // √z
    mpf_sqrt(three, r3);            // √3
    if mpf_is_ge(z, zero) then begin
      Jvx(pv, sz32, Ipv, true);     // I+v
      Jvx(mv, sz32, Imv, true);     // I-v
      mpf_sub(Imv, Ipv, Ai);        // α=I(-v) - I(+v)
      mpf_mul(Ai, rz, Ai);          // α√z
      mpf_div(Ai, three, Ai);       // Ai = (α√z)/3
      mpf_add(Imv, Ipv, Bi);        // β=I(-v) + I(+v)
      mpf_mul(Bi, rz, Bi);          // β√z
      mpf_div(Bi, r3, Bi);          // Bi = (β√z)/√3
//      Form1.memo1.Lines.Append( string('I+v = ' + mpf_decimal(Ipv, 50)));
//      Form1.memo1.Lines.Append( string('I-v = ' + mpf_decimal(Imv, 50)));
    end
    else begin
      Jvx(pv, sz32, Jpv, false);    // J+v
      Jvx(mv, sz32, Jmv, false);    // J-v
      mpf_add(Jmv, Jpv, Ai);        // α=J(-v) + J(+v)
      mpf_mul(Ai, rz, Ai);          // α√z
      mpf_div(Ai, three, Ai);       // Ai = (α√z)/3
      mpf_sub(Jmv, Jpv, Bi);        // β=J(-v) - J(+v)
      mpf_mul(Bi, rz, Bi);          // β√z
      mpf_div(Bi, r3, Bi);          // Bi=(β√z)/3
//      Form1.memo1.Lines.Append( string('J+v = ' + mpf_decimal(Jpv, 50)));
//      Form1.memo1.Lines.Append( string('J-v = ' + mpf_decimal(Jmv, 50)));
    end;
  end;

  mpf_clear3(pv, mv, az);
  mpf_clear5(z32, s23, rz, r3, s32);
  mpf_clear5(sz32, Ipv, Imv, Jpv, Jmv);
  mpf_clear4(g23, s16, p323, p316);
end;

// x 入力値限界
// XinMIN <= xin <= XinMAX  範囲外の場合誤差大きくなります。
// 誤差をなくす為には、演算桁数と、Σ値の上限kmax ベルヌーイ数用 NB値を大きく
// する必要が有ります、染ま場合最初の配列の準備の時間が長くなります。
const
  XinMIN = -80;
  XinMAX = 50;

// 計算
// xの値が大きくなると誤差が大きくなります。
procedure TForm1.Button1Click(Sender: TObject);
label
  EXT;
const
  N = 100;
  XLIN = 5;
  CHA = -3;
var
  ch, i, NN : integer;
  xin : double;
  xmin, xmax, dx, xg : double;
  xf, xm, Ai, Bi : mp_float;
  StopWatch : TStopwatch;
  ElapsedMillseconds : Int64;
  mm, ss, ms : integer;
begin
  memo1.Clear;
  memo1.Font.Size := 11;
  val(labelededit2.Text, xin, ch);
  if ch <> 0 then begin
    application.MessageBox('xの値に間違いがあります。','注意', 0);
    exit;
  end;

  if xin < XinMIN then begin
    application.MessageBox(PWideChar('xの絶対値は' + intTostr(XinMIN) + 'より大きくして下さい。'),'注意', 0);
    exit;
  end;
  if XinMAX > XinMAX then begin
    application.MessageBox(PWideChar('xの絶対値は' + intTostr(XinMAX) + 'より小さくして下さい。'),'注意', 0);
    exit;
  end;

  mpf_init4(xf, xm, Ai, Bi);

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

  application.ProcessMessages;

  mpf_read_decimal(xm, PAnsiChar(ansistring(labelededit2.Text + #00)));

  StopWatch := TStopwatch.StartNew;

  Airy_functions(xm, Ai, Bi);

  memo1.Lines.Append('エアリー関数');

  memo1.Lines.Append( string('Ai(x) = ' + mpf_decimal(Ai, 50)));
  memo1.Lines.Append( string('Bi(x) = ' + mpf_decimal(Bi, 50)));

  StopWatch.Stop;
  ElapsedMillseconds := StopWatch.ElapsedMilliseconds;

  ms := ElapsedMillseconds * N + 500;
  mm := ms div 60000;
  ss := (ms mod 60000) div 1000;
  NN := N;
  if (xin <= abs(CHA)) and (xin >= CHA) then
    memo1.Lines.Append('グラフ表示に約' + inttostr(mm) + '分' + inttostr(ss) + '秒必要です。')
  else begin
    memo1.Lines.Append('グラフ表示に約2秒必要です。');
    NN := N * 2;
  end;

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

// グラフ表示
  series3.AddXY(xin, mpf_todouble(Ai));
  series4.AddXY(xin, mpf_todouble(Bi));
  xmin := round(xin) - 8;
  xmax := xmin + 13;
  dx := (xmax - xmin) / NN;
  for i := 0 to NN do begin
    xg := dx * i + xmin;
    mpf_set_dbl(xf, xg);

    if xg > abs(CHA) then AiryL_functions(xf, Ai, Bi)
    else
      if xg < CHA then AiryS_functions(xf, Ai, Bi)
      else
        Airy_functions(xf, Ai, Bi);
    series1.AddXY(xg, mpf_todouble(Ai));
    series2.AddXY(xg, mpf_todouble(Bi));
  end;

  application.ProcessMessages;
EXT:
  mpf_clear4(xf, xm, Ai, Bi);
end;

// 初期設定
// 計算用配列準備
// ベッセル関数に与える変数の値がz=(2/3)x^(3/2)となり80で約4.8f倍、100とすると約6倍の666となるので
// (z/2)^2k の計算がオーバーフローしないようにする必要があり演算の有効桁数を大きくします。
// 通常の場合z=100で180  Airyの場合x=80で300となります。
// 有効桁数を大きくすると、Γ関数配列の準備に時間が掛かるので、お待ち表示します。
procedure TForm1.Setting;
var
  i, k : integer;
  N, D, tmp : mp_float;
  vm, avm, tmf, tmf0 : mp_float;
  nd, vk : mp_float;
begin
  mpf_set_default_decprec(300);         // 有効桁数300桁 50桁の精度に必要です。
  setlength(BM, NB + 1);                // ベルヌーイ数配列
  setlength(FA, KMmax + 1);             // K!配列
  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 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_init4(zero, one, two, four);
  mpf_init3(three, pai, log_2pis2);
  mpf_init4(vm, avm, tmf, tmf0);
  mpf_init2(nd, vk);

  mpf_set0(zero);
  mpf_set1(one);
  mpf_set_int(two, 2);
  mpf_set_int(three, 3);
  mpf_set_int(four, 4);
  mpf_set_pi(pai);

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


  Bernoulli_number_BigInteger;              //  ベルヌーイ数作成

  for i := 0 to NB do begin
    mpf_read_decimal(N, PAnsiChar(ansistring(NumeratorString[i] + #00)));
    mpf_read_decimal(D, PAnsiChar(ansistring(DenominatorString[i] + #00)));
    mpf_div(N, D, BM[i]);
  end;

  factorialMul(kMmax);                      // 0!~KMmax!

  mpf_div(one, three, vm);                  // v 1/3
  for k := 0 to KMmax do begin
    mpf_set_int(tmf, k);                    // k
    mpf_add(tmf, vm, tmf0);                 // v + k
    mpf_add(tmf0, one, vk);                 // vk= v + k + 1
    gammaMul(vk, PVG[k]);                   // Γ(v+k+1)
  end;
  mpf_chs(vm, avm);                         // -v  -1/3
  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])                  // Γ(v+k+1)
    else
      mpf_set0(MVG[k]);                     // Γ(v+k+1) = 0
  end;

  memo1.Clear;
  memo1.Font.Color := clBlack;
  memo1.Lines.Append('');
  memo1.Lines.Append('             準備完了');
  Labelededit2.EditLabel.Caption := 'x (' + inttostr(XinMIN) + '≦x≦' + inttostr(XinMAX) + ')';

  Button1.Enabled := True;

  mpf_clear3(N, D, tmp);
  mpf_clear4(vm, avm, tmf, tmf0);
  mpf_clear2(nd, vk);
end;

// スタート表示
procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Enabled := False;
  memo1.Clear;
  memo1.Font.Size := 18;
  memo1.Font.Color := clRed;
  memo1.Lines.Append('');
  memo1.Lines.Append('             計算用配列準備中');
  Timer1.Interval := 200;
  Timer1.Enabled := True;
end;

//
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  Setting;
end;

// 終了処理
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  i : integer;
begin
  for i := 0 to NB do mpf_clear(BM[i]);
  for i := 0 to KMmax do mpf_clear(FA[i]);
  for i := 0 to KMmax do mpf_clear(PVG[i]);
  for i := 0 to KMmax do mpf_clear(MVG[i]);
  mpf_clear4(zero, one, two, four);
  mpf_clear3(three, pai, log_2pis2);
end;

end.

ベッセル関数は、級数展開して計算しているので、それを整理したものが、次の様になります。

数学・物理通信 4巻3号 6巻9号 を参照してください。
"数学・物理通信 4巻3号" "数学・物理通信 6巻9号" をwebで検索すれば見つかります。
zの符号で計算を変える必要はありません。

プログラムリストはエアリー関数部分のみですが、ダウンロードのAiry_function.zipの中には、全てのプログラムが入っています。
n!Γ(n+2/3)3~(2n) と、n!Γ(n+4/3)3^(2n)は配列として先に用意しています。

// Power_series_ Airy関数 多倍長
// z   値
procedure  Airy_functions(z : mp_float; var Ai, Bi : mp_float);
Label
  EXT;
var
  n : integer;
  sz3np, sz3n, z3n, tmp, sz3b: mp_float;
  zh3, five, six : mp_float;
  p323, g23, p316 : mp_float;
begin
  mpf_init5(sz3np, sz3n, z3n, tmp, sz3b);
  mpf_init3(zh3, five, six);
  mpf_init3(p323, g23, p316);

  mpf_add(two, four, six);          // 6
  // z = 0 時のこのルーチンは無くても可 たんに0時の計算を速くする為
  if mpf_is0(z) then begin
    mpf_div(two, three, tmp);
    mpf_expt(three, tmp, p323);     // 3^(2/3)
    gammaMul(tmp, g23);             // Γ(2/3)
    mpf_div(one, p323, Ai);         // 1/3^(2/3)
    mpf_div(Ai, g23, Ai);           // Ai=1/3^(2/3)/Γ(2/3)

    mpf_div(one, six, tmp);         // 1/6
    mpf_expt(three, tmp, p316);     // 3^(1/6)
    mpf_div(one, p316, Bi);         // 1/3^(1/6)
    mpf_div(Bi, g23, Bi);           // Bi=1/3^(1/6)/Γ(2/3);
    goto EXT;
  end;

  mpf_add(one, four, five);                   // 5

  mpf_mul(z, z, zh3);                         // z * z
  mpf_mul(zh3, z, zh3);                       // z * z * z
  mpf_set1(z3n);                              // z^(3n)
  mpf_set0(sz3n);                             // Σ=0
  mpf_set0(sz3b);
  for n := 0 to KMmax do begin
    mpf_div(z3n, MVG[n], tmp);                // z^(3n)/(n!Γ(n+2/3)*3^(2n)
    mpf_add(sz3n, tmp, sz3n);                 // Σm
    mpf_sub(sz3n, sz3b, tmp);                 // Σm- Σback
    if mpf_is0(tmp) then break;
    mpf_copy(sz3n, sz3b);
    mpf_mul(z3n, zh3, z3n);                   // z^(3n)
  end;

  mpf_set1(z3n);                              // z^(3n)
  mpf_set0(sz3np);                            // Σp=0
  mpf_set0(sz3b);
  for n := 0 to KMmax do begin
    mpf_div(z3n, PVG[n], tmp);                // z^(3n)/(n!Γ(n+4/3)*3^(2n)
    mpf_add(sz3np, tmp, sz3np);               // Σp
    mpf_sub(sz3np, sz3b, tmp);                // Σp- Σback
    if mpf_is0(tmp) then break;
    mpf_copy(sz3np, sz3b);
    mpf_mul(z3n, zh3, z3n);                   // z^(3n)
  end;
  mpf_mul(sz3np, z, sz3np);                   // Σp

  mpf_div(two, three, tmp);                   // 2/3
  mpf_expt(three, tmp, tmp);                  // 3^(2/3)
  mpf_div(sz3n, tmp, Ai);                     // Σm / (3^(2/3))

  mpf_div(four, three, tmp);                  // 4/3
  mpf_expt(three, tmp, tmp);                  // 3^(4/3)
  mpf_div(sz3np, tmp, tmp);                   // Σp / (3^(4/3))
  mpf_sub(Ai, tmp, Ai);                       // Ai

  mpf_div(one, six, tmp);                     // 1/6
  mpf_expt(three, tmp, tmp);                  // 3^(1/6)
  mpf_div(sz3n, tmp, Bi);                     // Σm / (3^(1/6))

  mpf_div(five, six, tmp);                    // 5/6
  mpf_expt(three, tmp, tmp);                  // 3^(5/6)
  mpf_div(sz3np, tmp, tmp);                   // Σp / (3^(5/6))
  mpf_add(Bi, tmp, Bi);                       // Bi

EXT:
  mpf_clear5(sz3np, sz3n, z3n, tmp, sz3b);
  mpf_clear3(zh3, five, six);
  mpf_clear3(p323, g23, p316);
end;

級数展開 マクローリン展開

// 多倍長計算 マクローリン展開
procedure Airy_functions(z : mp_float; var Ai, Bi : mp_float);
var
  k, n3kp : integer;
  s313, g13, s323, g23, s316 : mp_float;
  Aid, Bid, Ais, Bis , tmp : mp_float;
  zh3, s0, s1, sd, k3 : mp_float;
  x3hk, k3p1, k3p2, tmf : mp_float;
  Ai0, Bi0 : mp_float;
begin
  mpf_init5(s313, g13, s323, g23, s316) ;
  mpf_init5(Aid, Bid, Ais, Bis, tmp);
  mpf_init5(zh3, s0, s1, sd, k3);
  mpf_init5(x3hk, k3p1, tmf, Ai0, Bi0);
  mpf_init(k3p2);

  mpf_div(one, three, tmp);           // 1/3
  mpf_expt(three, tmp, s313);         // 3^(1/3)
  gammaMul(tmp, g13);                 // Γ(1/3)

  mpf_div(two, three, tmp);           // 2/3
  mpf_expt(three, tmp, s323);         // 3^(2/3)
  gammaMul(tmp, g23);                 // Γ(2/3)

  mpf_div(one, two, tmp);             // 1/2
  mpf_div(tmp, three, tmp);           // 1/6
  mpf_expt(three, tmp, s316);         // 3^(1/6);

  mpf_mul(s323, g23, tmp);            // 3^(2/3) * Γ(2/3)
  mpf_div(one, tmp, Ai0);             // Ai0 = 1 / 3^(2/3) / Γ(2/3)

  mpf_mul(s313, g13, tmp);            // 3^(1/3) * Γ(1/3)
  mpf_div(one, tmp, Aid);             // Ai'0 = 1 / 3^(1/3) / Γ(1/3)
  mpf_chs(Aid, Aid);

  mpf_mul(s316, g23, tmp);            // 3^(1/6) * Γ(2/3)
  mpf_div(one, tmp, Bi0);             // Bi0 = 1 / 3^(1/6) * Γ(2/3)

  mpf_div(s316, g13, Bid);            // Bi'0  = 3^(1/6) / Γ(1/3);

  mpf_mul(z, z, tmp);                 // z^2
  mpf_mul(tmp, z, zh3);               // z^3

  mpf_set0(s0);                       // k = 0 初期値
  mpf_set0(sd);                       // backup
  mpf_set1(x3hk);                     // z^(3k)
  mpf_set1(k3p1);                     // 3k+1
  mpf_set1(k3);                       // 3k+1

  for k := 0 to KMmax do begin
    mpf_mul_int(three, k, tmp);       // 3k
    mpf_add(tmp, one, k3p1);          // 3k + 1
    mpf_mul(k3, k3p1, k3);            // 1.4.7..(3k+1)
    n3kp := (3 * k + 1);              // 3k + 1
    mpf_div(k3, FA[n3kp], tmp);       // 1.4.7..(3k+1)/(3k+1)!
    mpf_mul(tmp, x3hk, tmf);          // 1.4.7..(3k+1)/(3k+1)! * Z^(3k)
    mpf_add(s0, tmf, s0);             // Σ
    if mpf_is_eq(s0, sd) then break;
    mpf_copy(s0, sd);
    mpf_mul(x3hk, zh3, x3hk);         // (z^(3^k)
  end;

  mpf_set0(s1);                       // k=0 初期値
  mpf_set0(sd);                       // backup
  mpf_set1(x3hk);                     // z^(3k)
  mpf_set1(k3p2);                     // 1
  mpf_set1(k3);                       // 1
  for k := 0 to KMmax do begin
    mpf_mul_int(three, k, tmp);       // 3k
    mpf_add(tmp, two, k3P2);          // 3k + 2
    mpf_mul(k3, k3p2, k3);            // 2.5.8..(3k+2)
    n3kp := (3 * k + 2);              // 3k + 2
    mpf_div(k3, FA[n3kp], tmp);       // 2.5.8..(3k+2)/(3k+2)!
    mpf_mul(tmp, x3hk, tmf);          // 2.5.8..(3k+2)/(3k+2)! * z^(3k)
    mpf_add(s1, tmf, s1);             // Σ
    if mpf_is_eq(s1, sd) then break;
    mpf_copy(s1, sd);
    mpf_mul(x3hk, zh3, x3hk);         // (z^(3^k)
  end;
  mpf_mul(s1, z, s1);                 // z^(3k+1)

  mpf_mul(s0, Ai0, Ais);              // Ais = Σ0 * Ai(0)
  mpf_mul(s1, Aid, tmf);              // Σ1 * Ai'(0)
  mpf_add(tmf, Ais, Ai);              // Ai

  mpf_mul(s0, Bi0, Bis);              // Bis = Σ0 * Bi(0)
  mpf_mul(s1, bid, tmp);              // Σ1 * Bi'(0)
  mpf_add(tmp, Bis, Bi);              // Bi

  mpf_clear5(s313, g13, s323, g23, s316) ;
  mpf_clear5(Aid, Bid, Ais, Bis, tmp);
  mpf_clear5(zh3, s0, s1, sd, k3);
  mpf_clear5(x3hk, k3p1, tmf, Ai0, Bi0);
  mpf_clear(k3p2);
end;

 

前記マクローリン展開は分かりずらいので、次の展開式を検討

一次微分に関しては今回は省略

 Γ関数の使用をやめる為、Ai(0), Bi(0), Ai'(0), Bi'(0)は、定数として与えます。
計算結果の有効桁数は50桁ですが、140桁程度必要です、計算範囲はZ=-75~25程度です。
指定値のエアリー関数については、BigDecimalで計算します。
 BigDecimalの演算には、除算以外の計算には、桁数制限が無く桁数が大きくなりすぎて、演算出来なくなる場合があるので、適宜必要な桁数で丸め処理を行う必要があります。
此処の計算では、250桁に設定しています。
50桁の答えを表示する場合は、テキストで出力する直前で、50桁に丸めます。

const
  PRE = 250;                              // Bigdecimal 有効桁数

// 多倍長計算 BigDecimal マクローリン展開
procedure Airy_functions(x : Bigdecimal; var Ai, Bi : Bigdecimal);
const
  Ai0S = '3.55028053887817239260063186004183176397979174199177240583326510300810042450126712957174246054040271688420448730349495839758292670446161937E-1';
  AidS ='-2.58819403792806798405183560189203963479091138354934582210001813856102772676790280654196405827275384313371193211789133381275035952167626014E-1';
  Bi0S = '6.14926627446000735150922369093613553594728188648596505040878753014296519305520640529387343345267569240728438782242516724523554227287639109E-1';
  BidS = '4.48288357353826357914823710398828390866226799212262061082808778372330755009780647185046574400736362878496329249031699773802889479552819613E-1';
var
  k : integer;
  s0, s1, sb: Bigdecimal;
  s3kp1, s3kp2, k3p11h, k3p1h, k3p11 : Bigdecimal;
  k3p1, k3p2, kk3p1 : bigdecimal;
  xh3, sxh3, tmp : Bigdecimal;
  ai0, aid, bi0, bid : Bigdecimal;
begin
  s0 := '0';                            // 初期値 0
  sb := '0';                            // 0
  xh3 := x * x * x;                     // x^3
  sxh3 := '1';                          // 1   x^(3k)
  s3kp1 := '1';                         // 1   * 3(k+1)
  k3p1h := '1';                         // 1   (3(k+1))!
  for k := 0 to KMmax do begin
    sxh3 := sxh3 * xh3;                 // x^(3k)
    sxh3 := sxh3.RoundToPrecision(PRE);
    k3P1 := 3 * k + 1;                  // 3k+1
    s3kp1 := s3kp1 * k3P1;              // 1.4.7.(3k + 1);
    s3kp1 := s3kp1.RoundToPrecision(PRE);
    kk3p1 := 3 * (k + 1);               // 3*(k+1);
    k3p1h := k3p1h * (kk3p1 - 2) * (kk3p1 - 1) * (kk3p1); // (3*(k+1))!
    k3p1h := k3p1h.RoundToPrecision(PRE);
    tmp := s3kp1 * sxh3 / k3p1h;        // 1.4.7.(3k + 1) * x^(3k) / (3*(k+1))!
    s0 := s0 + tmp;                     // Σ
    s0 := s0.RoundToPrecision(PRE);
    if s0 = sb then break;
    sb := s0;
  end;
  s0 := s0 + 1;                         // 1 + Σ

  s1 := 0;                              // 初期値 0
  sb := 0;                              // x^3k
  sxh3 := '1';                          // x^(3k)
  s3kp2 := '1';                         // 1   *(3k+2)
  k3p11h := '1';                        // 1   (3*(k+1)+1)!
  for k := 0 to KMmax do begin
    sxh3 := sxh3 * xh3;                 // x^(3k)
    sxh3 := sxh3.RoundToPrecision(PRE);
    k3P2 := 3 * k + 2;                  // 3k+2
    s3kp2 := s3kp2 * k3P2;              // 2.5.8.(3k+2)
    s3kp2 := s3kp2.RoundToPrecision(PRE);
    k3p11 := 3 * (k + 1) + 1;           // 3*(k+1)+1
    k3p11h := k3p11h * (k3p11 - 2) * (k3p11 - 1) * (k3p11); // (3*(k+1)+1)!
    k3p11h := k3p11h.RoundToPrecision(PRE);
    tmp := s3kp2 * sxh3 / k3p11h;       // 2.5.8.(3k+2) * x^(3k) / ((3*(k+1)+1)!)
    s1 := s1 + tmp;                     // Σ
    s1 := s1.RoundToPrecision(PRE);
    if s1 = sb then break;
    sb := s1;
  end;
  s1 := s1 * x + x;                     // x + xΣ

  ai0 := Ai0S;
  aid := AidS;
  bi0 := Bi0S;
  bid := BidS;

  Ai := s0 * ai0;
  Ai := Ai + s1 * aid;
  Bi := s0 * bi0;
  Bi := Bi + s1 * bid;
end;

マクローリン展開を更に整理をすると次の様な簡単な、展開式になります。

 計算速度は、Airy functionの中で一番速く計算できます。

const
  PRE = 250;                              // Bigdecimal 有効桁数

// 多倍長計算 BigDecimal マクローリン展開
procedure Airy_functions(x : Bigdecimal; var Ai, Bi : Bigdecimal);
const
  Ai0S = '3.55028053887817239260063186004183176397979174199177240583326510300810042450126712957174246054040271688420448730349495839758292670446161937E-1';
  AidS ='-2.58819403792806798405183560189203963479091138354934582210001813856102772676790280654196405827275384313371193211789133381275035952167626014E-1';
  Bi0S = '6.14926627446000735150922369093613553594728188648596505040878753014296519305520640529387343345267569240728438782242516724523554227287639109E-1';
  BidS = '4.48288357353826357914823710398828390866226799212262061082808778372330755009780647185046574400736362878496329249031699773802889479552819613E-1';
var
  n : integer;
  s0, s1, sb: Bigdecimal;
  s23, s34 : Bigdecimal;
  xh3, sxh3, tmp : Bigdecimal;
  ai0, aid, bi0, bid : Bigdecimal;
begin
  s0 := 0;                            // 0
  sb := 0;                            // 0
  xh3 := x * x * x;                   // x^3
  sxh3 := xh3;
  s23 := 1;                           // 1
  for n := 1 to KMmax do begin
    s23 := s23 * (3 * n - 1) * (3 * n);   // (2,3),(5,6),,,((3n-1) * 3n)
    s23 := s23.RoundToPrecision(PRE);     // 桁数制限
    tmp := sxh3 / s23;                    // 除算は規定で桁数制限有り
    s0 := s0 + tmp;                       // s0 := s0 + (x^3)/((2,3),(5,6),,,)((3n-1) * 3n))
    s0 := s0.RoundToPrecision(PRE);       // 桁数制限
    if s0 = sb then break;                // Σ値が変化しなくなったら終了
    sxh3 := sxh3 * xh3;                   // x^6  9  12
    sxh3 := sxh3.RoundToPrecision(PRE);   // 桁数制限
    sb := s0;
  end;
  s0 := s0 + 1;

  s1 := 0;
  sb := 0;
  sxh3 := xh3;                            // x^3
  s34 := 1;
  for n := 1 to KMmax do begin
    s34 := s34 * (3 * n) * (3 * n + 1);   // (3,4),(6,7),,,(3n * (3n+1))
    s34 := s34.RoundToPrecision(PRE);     // 桁数制限
    tmp := sxh3 / s34;                    // 除算は規定で桁数制限有り
    s1 := s1 + tmp;                       // s1 := s1 + (x^3n)/((3,4),(6,7),,,(3n * (3n+1)))
    s1 := s1.RoundToPrecision(PRE);       // 桁数制限
    if s1 = sb  then break;               // Σ値が変化しなくなったら終了
    sxh3 := sxh3 * xh3;                   // x^6 9 12
    sxh3 := sxh3.RoundToPrecision(PRE);   // 桁数制限
    sb := s1;
  end;
  s1 := s1 * x + x;                       // x + xΣ   x + Σ(x^(3n+1)/(3n * (3n+1)))

  ai0 := Ai0S;
  aid := AidS;
  bi0 := Bi0S;
  bid := BidS;

  Ai := s0 * ai0;
  Ai := Ai + s1 * aid;
  Bi := s0 * bi0;
  Bi := Bi + s1 * bid;
end;

一般 Airy 関数

 一般 Airy関数の詳細については特殊関数 グラフィックスライブラリーを参照して下さい。
通常のAiry関数の次数ベッセル関数の次数V=1/3として計算していますが、一般 Airy関数では、次数V=1が通常のAiry 関数と同じになるようにして計算しています。
次数がV=-1だと無限大なるので、次数Vは-1より大きい値となります。

 次数vの値が-1だと、tanの値が無限大となります。
vの値が大きくなると、計算に大きな桁数が必要となるので、ここのプログラムでは、次数の最大値をv=4にしています。
 漸近計算が出来ないため、グラフの計算に時間が掛かるので、次数vの値が変更されない限り、グラフの曲線は再計算せず、指定値のみ計算します。



プログラム

// generalized Airy関数 多倍長
// pv. mv   J, I 用次数
// tanpis2    tan(π/(2v+4))
// v   generalized Airyの次数 v=1 が Airyの(1/3)vに相当
// z   値
procedure generalized_Airy_functions(pv, mv, tanpis2, v, z : mp_float; var Ai, Bi : mp_float);
label
  EXT;
var
  az: mp_float;
  vp2, s2vp2, vp2s2 : mp_float;
  bi0, ai0 : mp_float;
  harf, invvp2, tmp, tmf : mp_float;
  sqrtzsvp2, zij: mp_float;
  IJmv, IJpv : mp_float;
begin
  mpf_init(az);
  mpf_init3(vp2, s2vp2, vp2s2);
  mpf_init2(bi0, ai0);
  mpf_init4(harf, invvp2, tmp, tmf);
  mpf_init2(sqrtzsvp2, zij);
  mpf_init2(IJmv, IJpv);

  mpf_add(v, two, vp2);             // v + 2

  if mpf_is0(z) then begin
    mpf_div(one, two, harf);        // 1/2
    mpf_inv(vp2, invvp2);           // 1/(v+2)
    mpf_sub(invvp2, harf, tmp);     // 1/(v+2)-1/2
    mpf_expt(vp2, tmp, tmp);        // (v+2)^(1/(v+2)-1/2)
    mpf_sub(one, invvp2, tmf);      // 1-1/(v+2)
    gammaMul(tmf, tmf);             // Γ(1-1/(v+2));
    mpf_div(tmp, tmf, bi);          // bi0 = ((v+2)^(1/(v+2)-1/2))/Γ(1-1/(v+2))
    mpf_mul(tanpis2, bi, ai);       // ai0 = tan(π/(2v+4)) * Bi0
    goto EXT;
  end;

  mpf_abs(z, az);
  mpf_div(az, vp2, tmp);            // z/(v+2)
  mpf_sqrt(tmp, sqrtzsvp2);         // √z/(v+2)

  mpf_div(two, vp2, s2vp2);         // 2/(v+2);
  mpf_div(vp2, two, vp2s2);         // (v+2)/2
  mpf_expt(az, vp2s2, tmf);         // z^((v+2)/2)
  mpf_mul(tmf, s2vp2, zij);         // zij = 2/(v+2) * z^((v+2)/2)

  if mpf_is_gt(z, zero) then begin
    Jvx(mv, zij, IJmv, true);       // I-v
    Jvx(pv, zij, IJpv, true);       // I+v
    mpf_sub(IJmv, IJpv, tmf);       // I-v - I+v
    mpf_mul(tmf, sqrtzsvp2, tmp);   // (I-v - I+v) * √(z/(v+2)
    mpf_mul(tmp, tanpis2, Ai);      // Ai = (I-v - I+v) * √(z/(v+2) * tan(π/(2v+4))
    mpf_add(IJmv, IJpv, tmf);       // I-v + I+v
    mpf_mul(tmf, sqrtzsvp2, Bi);    // Bi := (I-v + I+v) * √(z/(v+2)
  end;

  if mpf_is_lt(z, zero) then begin
    Jvx(mv, zij, IJmv, false);      // J-v
    Jvx(pv, zij, IJpv, false);      // J+v
    mpf_add(IJmv, IJpv, tmf);       // J-v + J+v
    mpf_mul(tmf, sqrtzsvp2, tmp);   // (J-v + J+v) * √(z/(v+2)
    mpf_mul(tmp, tanpis2, Ai);      // Ai = (J-v + I+v) * √(z/(v+2) * tan(π/(2v+4))
    mpf_sub(IJmv, IJpv, tmf);       // J-v - J+v
    mpf_mul(tmf, sqrtzsvp2, Bi);    // Bi := (J-v - J+v) * √(z/(v+2)
  end;

EXT:
  mpf_clear(az);
  mpf_clear3(vp2, s2vp2, vp2s2);
  mpf_clear2(bi0, ai0);
  mpf_clear4(harf, invvp2, tmp, tmf);
  mpf_clear2(sqrtzsvp2, zij);
  mpf_clear2(IJmv, IJpv);
end;


download Airy_function.zip

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