• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    function
    <cmath>

    std::assoc_legendre

    namespace std {
      double
        assoc_legendre(unsigned int l,
                       unsigned int m,
                       double x);              // (1) C++17
      floating-point-type
        assoc_legendre(unsigned int l,
                       unsigned int m,
                       floating-point-type x); // (1) C++23
    
      Promoted
        assoc_legendre(unsigned int l,
                       unsigned int m,
                       Arithmetic x);          // (2) C++17
    
      float
        assoc_legendref(unsigned int l,
                        unsigned int m,
                        float x);              // (3) C++17
    
      long double
        assoc_legendrel(unsigned int l,
                        unsigned int m,
                        long double x);        // (4) C++17
    }
    

    概要

    ルジャンドル陪関数 (associated Legendre functions) を計算する。

    戻り値

    引数 l, m, x のルジャンドル陪関数 Plm(x)=(1x2)m/2dmdxmPl(x)for |x|1 を返す。右辺の Pl(x) はルジャンドル多項式 (legendre)。

    備考

    負の m の対応

    この標準関数は m が正の場合にしか対応していない。 一方でルジャンドル陪関数はロドリゲスの公式を用いて負の m に対して自然に拡張され、 このことは球面調和関数を定義する上でも使われる。 負の m に対してもルジャンドル陪関数を計算する必要がある場合は、関係式 Plm(x)=(1)m(lm)!(l+m)!Plm(x) を用いる必要がある。

    #include <cmath>
    
    // 負の m にも対応した実装例
    double assoc_legendre(unsigned l, int m, double x) {
      if (m >= 0)
        return std::assoc_legendre(l, (unsigned) m, x);
      else
        return std::pow(-1.0, m) * (std::tgamma(1.0 + l + m) / std::tgamma(1.0 + l - m)) * std::assoc_legendre(l, (unsigned) -m, x);
    }
    

    上記の例では簡単のために階乗をガンマ関数 n!=Γ(n+1) (tgamma) で計算しているが、 計算効率やオーバーフローなどを考えると、直接 (l+|m|)(l|m|+1) で割り算したり、係数を事前計算しておくなど工夫すると良い。

    #include <cmath>
    #include <iostream>
    
    void p(unsigned l, unsigned m) {
      for (double x : {-1., 0., 1.})
        std::cout << "assoc_legendre(" << l << ", " << m << ", " << x << ") = " << std::assoc_legendre(l, m, x) << "\n";
      std::cout << "\n";
    }
    
    int main() {
      p(0, 0); // P_0^0(x) = 1
      p(1, 0); // P_1^0(x) = x
      p(1, 1); // P_1^1(x) = (1 - x^2)^(1/2)
      p(2, 0); // P_2^0(x) = (3x^2 - 1) / 2
      p(2, 1); // P_2^1(x) = 3x (1 - x^2)^(1/2)
      p(2, 2); // P_2^2(x) = 3 (1 - x^2)
    }
    

    出力例

    assoc_legendre(0, 0, -1) = 1
    assoc_legendre(0, 0, 0) = 1
    assoc_legendre(0, 0, 1) = 1
    
    assoc_legendre(1, 0, -1) = -1
    assoc_legendre(1, 0, 0) = 0
    assoc_legendre(1, 0, 1) = 1
    
    assoc_legendre(1, 1, -1) = -0
    assoc_legendre(1, 1, 0) = -1
    assoc_legendre(1, 1, 1) = -0
    
    assoc_legendre(2, 0, -1) = 1
    assoc_legendre(2, 0, 0) = -0.5
    assoc_legendre(2, 0, 1) = 1
    
    assoc_legendre(2, 1, -1) = 0
    assoc_legendre(2, 1, 0) = -0
    assoc_legendre(2, 1, 1) = -0
    
    assoc_legendre(2, 2, -1) = 0
    assoc_legendre(2, 2, 0) = 3
    assoc_legendre(2, 2, 1) = 0
    
    

    バージョン

    言語

    • C++17

    処理系

    備考

    GCC (libstdc++)

    GCC 7.1.0–8.0.0 では l < m の場合 (Plm=0) std::domain_error を送出する。

    GCC 7.1.0–8.0.0 では (1)m 倍された値を返す。

    実装例

    閉形式

    Plm(x)=12ll!(1x2)m/2j=0(lm)/2(1)jl!(2l2j)!j!(lj)!(lm2j)!xlm2j

    漸化式

    Plm(x)=(2l1)xPl1m(x)(l+m1)Pl2m(x)lm;Pm1m(x)=0,Pmm(x)=(2m1)!!(1x2)m/2

    関連項目

    参照