プログラミング雑感  新JavaScript入門  JavaScript,Neo-Generation  掲示板  表紙
5. 多項式クラス(5)  7. 無限級数クラス(2) 
プログラミング雑感
Written 4/14/02
6. 無限級数クラス(1)
無限級数クラスを作ります。
実際には、x = 0 の近傍で展開されたべき級数を扱います。
なぜ作るの?
学生の頃 tanx の級数展開を計算したかったんですね。
sinx や cosx て簡単じゃないですか。 例えば sinx の一般項の係数 an は、
  an = (-1)(n-1)/2/n!  (n : 奇数)
     = 0             (n : 偶数)
 
と書けますね(高校の教科書にも書いてあったような気がする)。 でも、その割り算で求まるはずの tanx は難しい。
  sinx = x - x3/6 + ...
  cosx = 1 - x2/2 + ...
 
だから、
  tanx = sinx / cosx = x + x3/3 + ...
 
とこれくらいまではすぐに求まりますが、 大きい項の係数になってくると計算量が多くなってなんともならない。 解析的に求まるものかどうかも知らないし、 ここはプログラムを作りたいところです。
クラス名
Taylor展開ってよく使うことばなので Taylor としました。 でも x = 0 の近傍で展開してます。
ファイル
完成品が次のファイルです。
  taylor.h
 
でも、精度を低くしているとバグが出てくる感じ。 これから直していきます。
データ構造
プロトタイプを次のようにしました。
  template <class T>
  class Taylor : vector<T> {
      int     min;
      int     length;
  public:
      Taylor() { min = 0; }
      Taylor(T a, int l = 100) { min = 0; length = l; push_back(a); }
      Taylor(int a, int l = 100) { min = 0; length = l; push_back((T)a); }
      Taylor(string func, int maxlength);
      Taylor(const Taylor& t) {
          (vector<T>&)(*this) = t;
          min = t.min;
          length = t.length;
      }
      Taylor& operator =(const Taylor& t) {
          (vector<T>&)(*this) = t;
          min = t.min;
          length = t.length;
          return *this;
      }
      T operator ()(int i) const {
          i -= min; if(i < 0 || (int)size() <= i) throw(1);
          return operator [](i);
      }
      Taylor& operator +=(const Taylor& a);
      Taylor& operator -=(const Taylor& a);
      Taylor& operator *=(const Taylor& a);
      Taylor& operator /=(const Taylor& a);
      Taylor& operator ^=(int a);
      Taylor& operator ^=(fraction a);
      Taylor& operator +=(T a);
      Taylor& operator -=(T a);
      Taylor& operator *=(T a);
      Taylor& operator /=(T a);
      Taylor& operator +=(int a) {   operator +=((T)a); return *this; }
      Taylor& operator -=(int a) {   operator -=((T)a); return *this; }
      Taylor differential() const;
      Taylor integral() const;
      Taylor inverse() const;
      Taylor synthesize(const Taylor& a) const;
      int getMin() const { return min; }
      unsigned int size() const { return ((const vector<T>&)(*this)).size(); }
      int precision() const { return length; }
  private:
      void normalize();
  };
 
まず、このクラスは vector の派生クラスです。 この vector の各項が級数の係数になります。 そして、メンバ変数の min が最小次数です。 すなわち、
  2x + x^2 - 3x^3
 
という級数なら、
  2, 1, -3
 
という配列になります。
また、配列の前後に 0 が並ぶ場合は、 それは normalize という private なメンバ関数によりカットされます。 すなわち、
  min = 0
  0, 2, 1, -3, 0, 0
 
というデータ構造の級数は、
  min = 1
  2, 1, -3
 
となります。
精度
残りのメンバ変数 length を精度としています。
精度というのは例えば上の例で length = 5 なら、
  2x + x^2 - 3x^3 + 0x^4 + 0x^5
 
で、下から5項は正しく、x^6 以降の係数は分からないよ、ということです。 別の書き方をするとこうなります。
  2x + x^2 - 3x^3 + o(x^5)
 
定数を除き、全ての級数は無限級数で誤差を含み、 この前提でこれ以降の計算は行われます。
コンストラクタで精度を指定しますが、デフォルトは 100 です。 これくらいあれば普通はだいじょうぶでしょう。
コンストラクタ
コンストラクタは色々用意しています。
定数はその型のものと、あとコードの記述がきれいになるという理由で int を引数に取るものを用意しています。
あと、文字列を引数にとって次の関数を作成することもできます。
  x
  expx
  sinx
  cosx
 
具体的には次のように使います。
  Taylor<double>  x, f;
  x = Taylor<double>("x");              //x
  f = 2 * x + x * x - 3 * x * x * x;    //2x + x^2 - 3x^3
 
他にも特殊関数があったほうがよいかもしれません。
first, prev, next, exit