ディリクレラムダ関数

ディリクレラムダ関数λ(s)は、s=1に単純な極を持つ複素変数sの有理型複素数値関数です。この関数は、実数 s>1 の λ(s) を次の様に定義することによって構築されます。
          λ(s) = Σk=01/(2k + 1)s
次に、s = 1で保存して、複素平面の残りの部分に分析的に続行します、ディリクレラムダ関数は、リーマンゼータ関数で次のように表すことができます。
           λ(s)=(1-2-s)ζ(s)

 ディリクレラムダ関数は、インターネットで探してもあまり資料が見つかりません。

最初のプログラムはMathematics Source Library C & ASMにある Dirichlet Lambda function をDelphi に変換したものですが、リーマンのζ 関数が計算出来れば、簡単にディリクレλ 関数が計算出来ます。

プログラム1

unit main;

interface

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

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    BitBtn1: TBitBtn;
    LabeledEdit1: TLabeledEdit;
    Chart1: TChart;
    Series1: TLineSeries;
    Series3: TPointSeries;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

  LDBL_EPSILON : extended;

implementation

{$R *.dfm}

uses dirichlet_eta, Riemann_Zeta;

//==================================================================================================
// function Lambda_Star_Negative_Arg(s: extended): extended
//
// このルーチンは、s <0 のディリクレラムダスター関数を計算します。
//
// lambda *(s)=[(2^s -1)/(2^s] zeta*(s)- 1/2^s、
//    zeta*(s) はzeta*関数です。
//
//==================================================================================================
function Lambda_Star_Negative_Arg(s: extended): extended;
var
  zeta_star: extended;
  lambda_star: extended;
  two_minus_s: extended;
  two_minus_s1: extended;
begin
  zeta_star := xRiemann_Zeta_Star_Function(s);
  if abs(zeta_star) = MAXExtended then begin
    result := -zeta_star;
    exit;
  end;
  two_minus_s := power(2.0, -s);
  two_minus_s1 := two_minus_s - 1.0;
  if two_minus_s1 < 1 then
    two_minus_s1 := 1;                           // two_minus_s1が1と成る時1の筈だが最終ビット当たりに誤差が出ます
  if abs(zeta_star) > MAXExtended / two_minus_s1 then begin
    if zeta_star < 0.0 then  result :=  MAXExtended else result := -MAXExtended;
    exit;
  end;
  lambda_star := (1.0 - two_minus_s) * zeta_star;
  if lambda_star > 0.0 then begin
    result :=  lambda_star - two_minus_s;
    exit;
  end;
  if lambda_star < two_minus_s - MAXExtended then begin
    result := -MAXExtended;
    exit;
  end;
  result :=  lambda_star - two_minus_s;
end;

//==================================================================================================
// function Lambda_Star_Positive_Arg(s: extended): extended;
//  このルーチンは、s >= 0 のディリクレラムダスター関数を計算します。
//==================================================================================================
function Lambda_Star_Positive_Arg(s: extended): extended;
const
  LDBL_MAX_EXP = 16384;       // 64ビット(double)の時は1024
var
  zeta_star: extended;
  two_s: extended;
begin
  if s = 1.0 then begin
    result :=  MAXExtended;
    exit;
  end;
  zeta_star := xRiemann_Zeta_Star_Function(s);
  if s > LDBL_MAX_EXP then begin
    result := zeta_star;
    exit;
  end;
  two_s := power(2.0, s);
  result := ((two_s - 1.0) * zeta_star - 1.0) / two_s;
end;

//==================================================================================================
// function xDirichlet_Lambda_Star_Function(s: extended): extended;
//
// このルーチンは、次のように定義されたディリクレラムダスター関数を計算します。
//   λ*(s) = λ-1、
//  lambda()はディリクレラムダ関数です。
//
// lambda*(s)= [zeta*(s)+ eta*(s)] / 2 であることに注意してください。
//    zeta*はリーマンゼータスター関数と eta*はディリクレのイータスター関数です。
// sの値によって計算を選択します。
//==================================================================================================
function xDirichlet_Lambda_Star_Function(s: extended): extended;
begin
  if s = 0.0 then  begin
    result :=  -1.0;
    exit;
  end;
  if s > 0.0 then
    result :=  Lambda_Star_Positive_Arg(s)
  else
    result := Lambda_Star_Negative_Arg(s);
end;

//==================================================================================================
// function Dirichlet_Lambda_Star_Function(s: double): edouble;
//
// このルーチンは、次のように定義されたディリクレラムダスター関数を計算します。
//   λ*(s) = λ-1、
//  lambda()はディリクレラムダ関数です。
//
// lambda*(s)= [zeta*(s)+ eta*(s)] / 2 であることに注意してください。
//  zeta*はリーマンゼータスター関数と eta*はディリクレのイータスター関数です。
//==================================================================================================
function Dirichlet_Lambda_Star_Function(s: double): double;
var
  lambda_star: extended;
begin
  if s = 1 then begin
    result :=  MAXDouble;
    exit;
  end;
  lambda_star := xDirichlet_Lambda_Star_Function(s);
  if abs(lambda_star) >= MAXDouble then begin
    if lambda_star < 0.0 then  result := -MAXDouble else result := MAXDouble;
    exit;
  end;
  result := lambda_star;
end;

//==================================================================================================
// function xDirichlet_Lambda_Function(s: extended): extended;
//
// ディリクレラムダ関数は次のように定義されます
//   lambda(s)= Sum(1 /(2k + 1)^s)、 k = 0、...で合計されます。
//	sはRe(s)> 1の複素数です。
// 次に、解析的に複素平面の残りの部分に進みます。
// s = 1の場合、LDBL_MAXが返されます。//
// lambda(s)> LDBL_MAXの場合、LDBL_MAXが返され、
// lambda(s)<-LDBL_MAXの場合、-LDBL_MAXが返されます。
// lim lambda(s)= -inf、左からs-> 1、lim lambda(s)= inf 右からs-> 1。
//
// lambda(s)= [zeta(s)+ eta(s)] / 2であることに注意してください。
//   ここで、zetaはリーマンゼータ関数とetaはディリクレのイータ関数です。
//
// lambda(s)= 1 + lambda_star(s)
//==================================================================================================
function xDirichlet_Lambda_Function(s : extended): extended;
var
  lambda_star: extended;
begin
  if s = 1 then begin
    result := MAXExtended;
    exit;
  end;
  lambda_star := xDirichlet_Lambda_Star_Function(s);
  if abs(lambda_star) = MAXExtended then begin
    result := lambda_star;
    exit;
  end;
  result :=  1.0 + lambda_star;
end;

//==================================================================================================
// function Dirichlet_Lambda_Star_Function(s: double): double;
//
// このルーチンは、次のように定義されたディリクレラムダスター関数を計算します。
//  λ*(s) = λ(s)-1、
//     lambda()はディリクレラムダ関数です。//
//
// lambda*(s)= [zeta*(s)+ eta*(s)] / 2 であることに注意してください。
//    zeta*は リーマンゼータ*関数とeta*は ディリクレのイータスター関数です。
//==================================================================================================
function Dirichlet_Lambda_Function(s : double): double;
var
  lambda: extended;
begin
  if s= 1.0 then begin
    result := MAXDouble;
    exit;
  end;
  lambda := xDirichlet_Lambda_Function(s);
  if abs(lambda) >= MAXDouble then  begin
    if lambda < 0.0 then  result := -MAXDouble else result := MaxDouble;
    exit;
  end;
  result := lambda;
end;

//--------------------------------------------------------------------------------------------------
// 計算の実行とグラフ作成
//--------------------------------------------------------------------------------------------------
procedure TForm1.BitBtn1Click(Sender: TObject);
const
  n = 2000;
var
  Lambda, Lambdab: double;
  star: double;
  s : double;
  i : integer;
  min, max, dx: double;
begin
  val(LabeledEdit1.Text, s, i);
  if i <> 0 then begin
    MessageDlg('xの値に間違いがあります。', mtInformation,
      [mbOk], 0, mbOk);
    exit;
  end;
  Lambda := Dirichlet_Lambda_Function(s);
  star := Dirichlet_Lambda_Star_Function(s);
  Memo1.Clear;
  Memo1.Lines.Add('λ関数');
  // s = 1の時はMaxDoubleになるので∞を表示
  if s <> 1 then begin
    Memo1.Lines.Add('λ(x)      = ' + floatTostr(Lambda));
    Memo1.Lines.Text := Memo1.Lines.Text + 'λ(x) - 1 = ' + floatTostr(star);
//  Memo1.Lines.Add('λ(x) - 1 = ' + floatTostr(star));
  end
  else begin
    Memo1.Lines.Add('λ(x)      = ∞');
    Memo1.Lines.Text := Memo1.Lines.Text + 'λ(x) - 1 = ∞';
  end;
  Series1.Clear;
  Series3.Clear;
  if Lambda > 3 then Lambda := 3;
  if Lambda < -2 then Lambda := -2;
  Series3.AddXY(s, Lambda);
  min :=  - 10;
  if s < min then min := s;
  max :=  5;
  if s > max then max := s;
  dx := (max - min) / n;
  Lambdab := 1;
  for i := 0 to n do begin
    s := i * dx + min;
    Lambda := Dirichlet_Lambda_Function(s);
    if Lambda > 3 then Lambda := 3;
    if (Lambdab = -2) and (Lambda = 3) then begin
      Series1.AddXY(s, Lambdab, '', clBlue);
      Series1.AddXY(s, Lambda, '', clBlue);
    end;
    if Lambda < -2 then Lambda := -2;
    if (Lambda < 3) and (Lambda > -2) then Series1.AddXY(s, Lambda, '', clBlue)
                                      // グラフのベースの色と同じにして見えなくします。
                                      else Series1.AddXY(s, Lambda, '', clBtnFace);
    Lambdab := Lambda;
  end;
end;

//-------------------------------------------
// extended の Epsilon 設定
//-------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
var
  d, m: extended;
begin
  Memo1.Clear;
  LDBL_EPSILON := 1;
  d := 1;
  repeat
    LDBL_EPSILON := LDBL_EPSILON / 2;
    m := d + LDBL_EPSILON;
  until m = d;
  LDBL_EPSILON := LDBL_EPSILON * 2;
end;

end.
unit Riemann_Zeta;

interface

function xRiemann_Zeta_Star_Function(s: extended): extended;

implementation

uses system.math, dirichlet_eta;

//------------------------------------------------------------------------------
// function xRiemann_Zeta_Star_Function(s : extended): extended;
//
//  Description:
//     This routine calculates the Riemannt zeta star function defined as
//                           zeta*(s) = zeta(s) - 1,
//     where zeta() is the Riemann zeta function for real s != 1.
//------------------------------------------------------------------------------
function xRiemann_Zeta_Star_Function(s: extended): extended;
var
  two_s: extended;
  eta: extended;
  temp: extended;
begin
  two_s := power(2.0, s - 1.0);
  eta := xDirichlet_Eta_Star_Function(s);
  if s = 1.0 then begin
    result := MAXDouble;
    exit;
  end;
  if s < 0.0  then begin
    two_s := 1.0 / two_s;
    result := (eta + two_s) / (1.0 - two_s);
    exit;
  end;
  temp := two_s - 1.0;
  result := (two_s * eta + 1.0) / temp;
end;

end.
unit Gamma_Function;

interface
  function xGamma_Function(x: extended): extended;

implementation

uses system.math;

const
  LONG_MAX = 2147483647;
  max_long_double_arg: extended = 1755.5;
  g =  9.65657815377331589457187;
  e =  2.71828182845904523536028747;
  exp_g_o_sqrt_2pi = 6.23316569877722552586386e+3;
  a: array[0..8] of extended = (
                                +1.14400529453851095667309e+4,
                                -3.23988020152318335053598e+4,
                                +3.50514523505571666566083e+4,
                                -1.81641309541260702610647e+4,
                                +4.63232990536666818409138e+3,
                                -5.36976777703356780555748e+2,
                                +2.28754473395181007645155e+1,
                                -2.17925748738865115560082e-1,
                                +1.08314836272589368860689e-4
                               );

function xGamma(x: extended): extended; forward;

//=============================================================================
//
// この関数はLanczosの式を使用して実際のGamma(x)を計算します。
// xの範囲は -(max_long_double_arg-1) < x < max_long_double_arg。
// ガンマ関数は複素平面で有理型であり、正でない整数の値
// xaの正の整数または半分の正の整数をテストすると、
// 最大絶対相対誤差は約3.5e-16です。
//
// x > max_long_double_argの場合、lnGamma(x)を使用する必要があります。
// x < 0 の場合、ln(Gamma(x)) は複素数になる可能性があることに注意してください。
//
// 戻り値
//  xが正で、max_long_double_argより小さい場合、Gamma(x)
//  が返され、x > max_long_double_argの場合、maxextendedが返されます。
//  xが正でない整数の場合、maxextendedが
//  返されます(Gamma(x)は値の両側で符号を変更することに注意してください)。
//  xが非正の非整数の場合でx>-(max_long_double_arg + 1)の場合
//  Gamma(x)が返されます。それ以外の場合は0.0が返されます
//
//=============================================================================
function xGamma_Function(x: extended): extended;
var
  sin_x: extended;
  rg: extended;
  ix: int64;
begin
  if x > 0 then
    if x <= max_long_double_arg then begin
      result := xGamma(x);
      exit;
    end
    else begin
      result := maxextended;
      exit;
    end;
  if x > -LONG_MAX then begin
    ix := round(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;
  if x < - max_long_double_arg - 1 then begin
    result := 0;
    exit;
  end;
  rg := xGamma(1 - x) * sin_x / pi;
  if rg <> 0 then result := 1 / rg
             else result := maxextended;
end;

//=============================================================================
//
// この関数は倍数公式を使用してGamma(two_x)を返します。
//
//=============================================================================
function Duplication_Formula(two_x: extended): extended;
var
  x: extended;
  g: extended;
  n: integer;
begin
  x := 0.5 * two_x;
  n := round(two_x) - 1;
  g := power(2.0, two_x - 1.0 - n);
  g := g * power(2, n);
  g := g / sqrt(pi);
  g := g * xGamma_Function(x);
  g := g * xGamma_Function(x + 0.5);
  result := g;
end;

//=============================================================================
//
// この関数はLanczosの式を使用して実際のGamma(x)を計算します。
// x、ここで0<x<=900。900<x<1755.5の場合、倍数公式を使用します。
// 関数power()。結果の相対誤差は約10^-16です。x = 0付近を除きます。
// x>1755.5の場合、lnGamma(x)を計算する必要があります。
// xが正で1755.5未満の場合、Gamma(x)が返され、
// x>1755.5の場合、maxextendedが返されます。
//
//=============================================================================
function xGamma(x: extended): extended;
var
  xx: extended;
  temp: extended;
  n, i: integer;
  xx2 : extended;
begin
  if x < 1 then xx := x + 1 else xx := x;
  n := sizeof(a) div sizeof(extended);
  if x > max_long_double_arg then begin
    result := maxextended;
    exit;
  end;
  if x > 900 then begin
    result := Duplication_Formula(x);
    exit;
  end;
  temp := 0;
  for i := n - 1 downto 0 do temp := temp + a[i] / (xx + i);
  temp := temp + 1;
  xx2 := (xx - 0.5) / 2;
  temp := temp * (power((g + xx - 0.5) / e, xx2) / exp_g_o_sqrt_2pi );
  temp := temp * power((g + xx - 0.5) / e, xx2);      // X64 オーバーフロー対策
  if x < 1 then result := temp / x
           else result := temp;
end;

end.

プログラム2

unit main;

interface

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

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    BitBtn1: TBitBtn;
    LabeledEdit1: TLabeledEdit;
    Chart1: TChart;
    Series1: TLineSeries;
    Series3: TPointSeries;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function Gamma(x: Extended): Extended;  // ガンマ関数
const
//ベルヌーイ数B(2)、B(4)、B(6)、...、B(16)
  B : array[1..8] of Extended = ( 1.0 / 6,           // B(2)
                                  -1.0 / 30,
                                   1.0 / 42,
                                  -1.0 / 30,
                                   5.0 / 66,
                                -691.0 / 2730,
                                   7.0 / 6,
                               -3617.0 / 510);     // B(16)

  m: integer = sizeof(B) div sizeof(Extended);
var
  i : integer;
  sum : Extended;
  xx, v  : Extended;
  xj  : Extended;
  lng : Extended;
  ln_sqrt_2pi: Extended;
begin
  ln_sqrt_2pi := ln(sqrt(2 * pi));                    // = ln(2 * pi) / 2;
  sum := 0;
  v := 1;
  while x < m do begin
    v := v * x;
    x := x + 1;
  end;
  xx := x * x;
  xj := x;
  lng := ln_sqrt_2pi - x + (x - 0.5) * ln(x) - ln(v);
  for i := 1 to  m do begin
    sum := sum + B[i] / (i * 2 * (2 * i - 1)) / xj;
    xj := xj * xx;
  end;
  result := exp(sum + lng);
end;

// ========================================================================
// x が -5 より小さくなりと誤差が大きくなります
//=========================================================================
function Riemann_Zeta_Function(x: extended): extended;
const
  N = 8;
  coef: array[0..19] of extended = (
	 8.333333333333333333333333333e-2,  //  1/12
	-1.388888888888888888888888889e-3,  // -1/720
	 3.306878306878306878306878307e-5,  //  1/30240
	-8.267195767195767195767195767e-7,  // -1/1209600
	 2.087675698786809897921009032e-8,  //  1/47900160
	-5.284190138687493184847682202e-10,
	 1.338253653068467883282698098e-11,
	-3.389680296322582866830195391e-13,
	 8.586062056277844564135905450e-15,
	-2.174868698558061873041516424e-16,
	 5.509002828360229515202652609e-18,
	-1.395446468581252334070768626e-19,
	 3.534707039629467471693229977e-21,
	-8.953517427037546850402611251e-23,
	 2.267952452337683060310950058e-24,
	-5.744790668872202445263829503e-26,
	 1.455172475614864901866244572e-27,
	-3.685994940665310178130050728e-29,
	 9.336734257095044668660153106e-31,
	-2.365022415700629886484029550e-32
  );

var
  i, N2 : integer;
  powNx, w, z, zprev: extended;
begin
  if x = 1 then begin
    result := infinity;
    exit;
  end;
  z := 1;
  for i := 2 to N - 1 do begin
    zprev := z;
    z := z + power(i, -x);
    if z = zprev then begin
      result :=  z;
      exit;
    end;
  end;
  N2 := N * N;
  powNx := power(N, x);
  w := x / (N * powNx);
  z := z + 0.5 / powNx + N / ((x - 1) * powNx) + coef[0] * w;
  i := 1;
  while  (i < 20) and (z <> zprev) do begin
    w := w * (x + 2 * i - 1) * (x + 2 * i) / (N2);
    zprev := z;
    z := z + coef[i] * w;
    inc(i);
  end;
  result := z;
end;

function RiemannFunction(s: Extended): Extended;
var
  term : Extended;
  ints : integer;
  def : Extended;
begin
  ints := trunc(s);
  def := s - ints;
  if (s <= -2) and (def = 0) and (ints mod 2 = 0) then
    result := 0
  else
  if s < -1 then begin                                       // -s 時誤差が大きくなるのでζを+で計算します
    term := power(2, s) * power(pi, s - 1) * sin(pi * s / 2);
    result := term * Riemann_Zeta_Function(1 - s) * Gamma(1 - s);
  end
  else
    result := Riemann_Zeta_Function(s);
end;

function Dirichlet_Lambda_Function(x: extended): extended;
begin
  result := (1 - power(2, -x)) * RiemannFunction(x);
//  result := power(2, -x) * (power(2, x) - 1) * Riemann_Zeta_Function(x);
end;

//------------------------------------------------------------------------------
// 計算の実行とグラフ作成
//------------------------------------------------------------------------------
procedure TForm1.BitBtn1Click(Sender: TObject);
const
  n = 2000;
var
  Lambda, Lambdab: extended;
  star: extended;
  s : extended;
  i : integer;
  min, max, dx: extended;
begin
  val(LabeledEdit1.Text, s, i);
  if i <> 0 then begin
    MessageDlg('xの値に間違いがあります。', mtInformation,
      [mbOk], 0, mbOk);
    exit;
  end;
  Lambda := Dirichlet_Lambda_Function(s);
  star := Lambda - 1;
  Memo1.Clear;
  Memo1.Lines.Add('λ関数');
  Memo1.Lines.Add('λ(s)      = ' + floatTostr(Lambda));
  Memo1.Lines.Text := Memo1.Lines.Text + 'λ(s) - 1 = ' + floatTostr(star);
  Series1.Clear;
  Series3.Clear;
  if Lambda > 3 then Lambda := 3;
  if Lambda < -2 then Lambda := -2;
  Series3.AddXY(s, Lambda);
  min :=  -10;
  if s < min then min := s;
  max :=  5;
  if s > max then max := s;
  dx := (max - min) / n;
  Lambdab := 1;
  for i := 0 to n do begin
    s := i * dx + min;
    Lambda := Dirichlet_Lambda_Function(s);
    if Lambda > 3 then Lambda := 3;
    if (Lambdab = -2) and (Lambda = 3) then begin
      Series1.AddXY(s, Lambdab, '', clBlue);
      Series1.AddXY(s, Lambda, '', clBlue);
    end;
    if Lambda < -2 then Lambda := -2;
    if (Lambda < 3) and (Lambda > -2) then Series1.AddXY(s, Lambda, '', clBlue)
                                // グラフのベースの色と同じにして見えなくします。
                                else Series1.AddXY(s, Lambda, '', clBtnFace);
    Lambdab := Lambda;
  end;
end;

end.

 
  download dirichlet_Lambda_function.zip

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