log(1+x)/xを有理関数で近似するとき、テーラー展開で4次まであわせると、
となったが、4次まであわせるには、
という形などが考えられる。
その中から最適なものを選ぶべきではないだろうか。
一般に、近似したい関数を、
として、n次までの近似を求めたいとき、
ただし、l + m = n
が考えられる。
最初の例は連分数から有理関数を得たが、この考え方で求めてみよう。
ただし、
このとき、 でなければならないから、
(↑これ思いつくのに数日かかった)
この連立方程式、
を解いて、
となり、上の結果と一致した。
一般には、
...
ただし、c_k = 0 (k < 0)
これは、連立一次方程式だから、b1, ..., bmについて解ける。
さらに、
...
より、a1, ..., alについても求められる。
求められた多項式をhlと書くと、
ソースは一部のみ。
#include
#include "taylor.h"typedef vector
Vec;
typedef vectorMatrix;
typedef TaylorPoly; void solve(int n, int l);
fraction getTerm(int i);
void make_matrix(Matrix& mat, int n, int m);
void solve_matrix(Matrix& mat, Vec& b, int n);
void calc_a(Vec& a, const Vec& b, int l, int m);void main(int argc, char **argv) {
if(argc != 2) {
cerr << "usage : log4 n." << endl;
exit(1);
}
int n = atoi(argv[1]);
for(int l = 0; l <= n; l++)
solve(n, l);
}void solve(int n, int l) {
int m = n - l;
Vec a(l+1);
Vec b(m+1);
Matrix mat(m);
make_matrix(mat, n, m);
solve_matrix(mat, b, n);
calc_a(a, b, l, m);
a[0] = b[0] = 1;
Poly x("x");
Poly f, g;
for(int i = l; i >= 0; i--)
f = f * x + a[i];
for(int i = m; i >= 0; i--)
g = g * x + b[i];
cout << f << endl;
cout << g << endl;
// cout << f / g << endl;
}fraction getTerm(int i) {
return fraction(i & 1 ? -1 : 1, i + 1);
}void make_matrix(Matrix& mat, int n, int m) {
int l = n - m;
for(int i = 0; i < m; i++) {
mat[i].resize(m + 1);
for(int k = 0; k < m; k++) {
int index = i - k + l;
mat[i][k] = index >= 0 ? getTerm(index) : 0;
}
mat[i][m] = getTerm(l + i + 1) * -1;
}
}void solve_matrix(Matrix& mat, Vec& b, int n) {
int m = (int)b.size() - 1;
// 上三角に
for(int i = 0; i < m; i++) {
if(mat[i][i].getBunsi() == 0) {
// 対角が0にならないものを探してスワップ
for(int j = i + 1; j < m; j++) {
if(mat[j][i].getBunsi() != 0) {
Vec tmp = mat[i];
mat[i] = mat[j];
mat[j] = tmp;
break;
}
}
}
// 対角を1に
for(int k = i + 1; k <= m; k++)
mat[i][k] /= mat[i][i];
mat[i][i] = 1;
// 対角成分より下を0に
for(int j = i + 1; j < m; j++) {
for(int k = i + 1; k <= m; k++)
mat[j][k] -= mat[j][i] * mat[i][k];
}
}
// 残りの非対角成分も0に
for(int i = 1; i < m; i++) {
for(int j = 0; j < i; j++) {
for(int k = i + 1; k <= m; k++)
mat[j][k] -= mat[i][k] * mat[j][i];
}
}
// 解をコピー
for(int i = 0; i < m; i++)
b[i+1] = mat[i][m];
}void calc_a(Vec& a, const Vec& b, int l, int m) {
for(int i = 1; i <= l; i++) {
a[i] = getTerm(i);
for(int k = 1; k <= m; k++) {
int index_c = i - k;
if(index_c >= 0)
a[i] += getTerm(index_c) * b[k];
}
}
}