6. 無限級数クラス(1)
学生の頃 tan
x の級数展開を計算したかったんですね。
sin
x や cos
x て簡単じゃないですか。
例えば sin
x の一般項の係数 a
n は、
an = (-1)(n-1)/2/n! (n : 奇数)
= 0 (n : 偶数)
と書けますね(高校の教科書にも書いてあったような気がする)。
でも、その割り算で求まるはずの tan
x は難しい。
sinx = x - x3/6 + ...
cosx = 1 - x2/2 + ...
だから、
tanx = sinx / cosx = x + x3/3 + ...
とこれくらいまではすぐに求まりますが、
大きい項の係数になってくると計算量が多くなってなんともならない。
解析的に求まるものかどうかも知らないし、
ここはプログラムを作りたいところです。
完成品が次のファイルです。
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
他にも特殊関数があったほうがよいかもしれません。