関数cbessel マニュアル

(The documentation of function cbessel)

Last Update: 2023/11/14


◆機能・用途(Purpose)

複素変数に対するベッセル関数を計算する。
Compute the Bessel function for a complex variable.

ベッセル関数は (1)Jn(z)=(z2)nk=0(1)k(z/2)2kk!(n+k)! によって定義され、漸化式 (2)Jm1(z)+Jm+1(z)=2mzJm(z) によって計算できる。
The Bessel function is defined by Eq. (1) and can be computed recursively using Eq. (2).


◆形式(Format)

#include <mathfunc.h>
inline double complex cbessel(const int n,const double complex z)


◆引数(Arguments)

n ベッセル関数Jn(z)の次数n。非負でなければならない。
The order n of the Bessel function Jn(z), which must be non-negative.
z ベッセル関数Jn(z)の引数zの値。
The value of the argument z for the Bessel function Jn(z).


◆戻り値(Return value)

引数で指定したnzの組に対するJn(z)の値。
The value of Jn(z) for n and z specified by the arguments.


◆使用例(Example)

double complex J=cbessel(1,0.5);


◆計算方法(Computation method)

●概要 (Outline)

この関数ではベッセル関数の漸化式(2)を 後ろ向きに利用する(Millerの方法と呼ばれる)。 はじめに十分に大きな整数Nを選び、JN+1(z)=0が成り立つものとする。 0mNについて (3)jm(z)Jm(z)JN(z) とおけば (4)jN+1(z)=0 (5)jN(z)=1 (6)jm1(z)=2mzjm(z)jm+1(z)(1mN) が成り立つので、これを用いて jN1(z),jN2(z),,j0(z) を順次求める。最後に (7)J0(z)+2m=1J2m(z)=JN(z){j0(z)+2m=1j2m(z)}=1 を用いてJN(z)を決定すれば欲しいnに対するJn(z)が得られる。
This function applies the recursive formula for the Bessel function (Eq. 2) in the backward order (known as Miller's algorithm). First, the program chooses a sufficiently large integer number N, for which JN+1(z)=0 is assumed. For 0mN, define jm(z) by (3), which satisfies Eqs. (4)-(6). From these equations, jN1(z),jN2(z),,j0(z) can be calculated one after another. Finally, Eq. (7) is applied to estimate JN(z), which enables us to compute Jn(z) for the specified n.


Nの決定 (Determination of N)

Press et al. (1988)によれば、N=2(n+an)とすることで 有効桁数a桁の計算が可能になるとのことである。 この関数で用いるdouble型変数の有効桁数は15桁程度であるので a=152=225とすれば良い。 但し、実際の計算精度はzにも依存すると思われるので この式をこのまま使うことには幾分か不安がある。 そこで多少の余裕をみてa=202=400とするとともに、 特にnの値が小さい場合にNが小さくなり過ぎないように 最低でもN=100以上とするという条件を加えた。 またzを正の実数値とした計算ではzNになると 数値不安定が起きることも分かったのでNの値に|z|を加えるようにした。 最終的に用いている計算式は (8)N=max{100,2(n+400n)}+|z| である。
According to Press et al. (1988), N=2(n+an) enables a computation in an accuracy of approximately a-digits. Because a double-type variable, used in this function, has an accuracy of about 15 digits, appropriate a may be estimated as a=152=225. However, the accuracy may depend on z, which is not considered in the reference. To safely avoid errors taking into account this uncertainty, I used a=202=400 instead, and required the minimum N value to be 100. In addition, a numerical test using a positive real z value suggested that a numerical instability occured when zN. Therefore |z| was added to N. The final equation used in the program is Eq. (8).


●ループ処理の高速化 (Coding for a faster loop)

プログラムの核となるのは漸化式を後ろ向きに用いる部分である。 この部分に対する単刀直入なコーディングとしては以下のCode 1が考えられる。 ここでJmm,Jm,Jmpはそれぞれjm1, jm, jm+1を表す。 The main part of the program is the backward application of the recursive formula. A direct coding for this part may be the Code 1 below, where “Jmm”, “Jm”, and “Jmp” represent jm1, jm, and jm+1, respectively.

(Code 1)
for(m=N;m>=1;m++){
    Jmm=2.0∗m∗Jm/z-Jmp;
    Jmp=Jm;
    Jm=Jmm;
}

Code 1ではループ内の2番目と3番目は単なる変数のコピーであり、 変数をうまく定義することによって削ることができる。 この改良を行ったのがCode 2であり、 連続した3つのmについて続けて漸化式を適用することによって 不要な変数コピー処理を回避して高速化を実現している。 数値テストの結果、この改良によって 関数内の他の処理も含めたトータルの処理時間が 2/3倍程度まで削減できることが確認できた。 Code 2におけるJm1,Jm2,Jm3の定義は 表1に示した通りである。 この関数ではCode 2を基本的な枠組みとしてコーディングを行っている。
The second and third processings in the loop in “Code 1” are simply a copying operation, which can be removed by better defining the variables. The result is “Code 2”, in which the recursive formulas for three consecutive m values are consequently applied in a loop. This enables a faster processing by avoiding unnecessary variable-copying operations. A numerical test indicated that this improvement reduces the total processing time, including the other processings in the function, can be reduced to about two-thirds. Definitions of “Jm1”, “Jm2”, and “Jm3” are listed in Table 1. The “Code 2” is used as a basic frame of this function code.

(Code 2)
for(m=N-1;m>=3;m-=3){
    Jm3=2.0∗(m+1)∗Jm1/z-Jm2;
    Jm2=2.0∗m∗Jm3/z-Jm1;
    Jm1=2.0∗(m-1)∗Jm2/z-Jm3;
}

表1. 変数Jm1,Jm2,Jm3の定義。
Table 1. The definitions of variables “Jm1”, “Jm2”, and “Jm3”.
変数
Variable
ループ前
Before loop
ループ後
After loop
Jm3jm+3jm
Jm2jm+2jm1
Jm1jm+1jm2


●その他の変数 (Other variables)

この関数では全てのmに対するjmを保存することはしない。 欲しいnに対するjnのみを保存しておく。 これを保存するための変数がJnである。
In this function, jm for each m is not preserved; only the jn for the required n is preserved. For this purpose, a variable “Jn” is used.

ほかに必要になるのが(7)式に登場する (9)j0(z)+2m=1j2m(z) である。これを表す変数がJm_sumである。 Jm_sumは最初に0に初期化しておき、 漸化式を後ろ向きに用いるループの中で 偶数番目のmが登場するたびにjmをJm_sumに加算していき、 最後に全体を2倍してj0を加えることでJm_sumを得る。
In addition, a variable defined by Eq. (9) is required to be preserved in order to apply the Eq. (7). For this purpose, a variable “Jm_sum” is used. This variable is initialized to zero, added by jm in the loop with regard to m whenever an even m value appears, and finally multiplied by 2 and added by j0 to obtain the final value of “Jm_sum”.


●オーバーフローの回避 (Avoiding over flows)

mが小さくなるにつれてjmの値は急激に大きくなるので 簡単にオーバーフローが起きてしまう。 これを回避するために関数ではjm10100を超えた時点で jm, jn, およびJm_sumを全て10100で割る。 これを行うと(7)式から計算されるJNの値が 10100倍されるが、jnの値は10100倍されているので (3)式から得られるJnの値は変わらない。
Since jm rapidly increases when m decreases, a overflow easily occurs. To avoid this, jm, jn, and “Jm_sum” are all divided by 10100 when jm exceeds 10100. By this operation, the JN value estimated by Eq. (7) is multiplied by 10100 but at the same time jn is multiplied by 10100. Therefore, the Jn value estimated by Eq. (3) does not change by this operation.


◆検証(Validation)

zとして正の実数値を利用した計算では 0n3, 0.01z1000の範囲において C言語標準関数であるj0, j1, jnを用いた計算の結果と非常に良く一致した。
For positive real z values, excellent fits with results of computations using C standard functions j0, j1, and jn were obtained for 0n3 and 0.01z1000.


◆引用文献(References)