誰もが言ったように、根のすべてまたは一部 (1 より大きい場合) を見つけるための一般的なアルゴリズムを提供することは不可能です。多くの関数には無数の根があるため、一般にすべての根を見つけることはできません。
ニュートンのような方法でさえ、常に解に収束するとは限りません。私は、関数が符号を変えることが知られているブラケットなど、合理的な状況下で解に収束する、優れたかなり安定した方法を好む傾向があります。単一根での収束動作が良好でありながら、関数の動作があまり良くない場合でも、基本的に二分法のように動作するように保護されているコードを見つけることができます。
したがって、まともなルート検索スキームがあれば、デフレなどの簡単なことを試すことができます。したがって、第 1 種ベッセル関数のような単純な関数を考えてみましょう。MATLAB を使用してすべての例を作成しますが、MATLAB の fzero のように、適切に作成された安定したルートファインダーを備えたツールで十分です。
ezplot(@(x) besselj(0,x),[0,10])
grid on
f0 = @(x) besselj(0,x);
xroots(1) = fzero(f0,1)
xroots =
2.4048
プロットから、5 または 6 付近に 2 番目のルートがあることがわかります。
ここで、そのルートの f0 を収縮させ、f0 に基づいて新しい関数を作成しますが、xroots(1) にルートがありません。
f1 = @(x) f0(x)./(x-xroots(1));
ezplot(f1,[0,10])
grid on
この曲線では、xroots(1) の f0 のルートが存在しないかのように取り除かれていることに注意してください。2 番目のルートを見つけることができますか?
xroots(2) = fzero(f1,2)
xroots =
2.4048 5.5201
もちろん続行できますが、ある時点でこのスキームは数値の問題で失敗します。そして、その失敗もそれほど長くはかかりません。
より良いスキームは、(1-d 問題の場合) サンプリング手法と組み合わせたブラケット スキームを使用することです。根を収縮させるために初期関数を変更する必要がないので、私はより良いと言います。(もちろん、2 次元以上の場合は、さらに複雑になります。)
xlist = (0:1:10)';
flist = f0(xlist);
[xlist,flist]
ans =
0 1.0000
1.0000 0.7652
2.0000 0.2239
3.0000 -0.2601
4.0000 -0.3971
5.0000 -0.1776
6.0000 0.1506
7.0000 0.3001
8.0000 0.1717
9.0000 -0.0903
10.0000 -0.2459
ご覧のとおり、関数は区間 [2,3]、[5,6]、および [8,9] で符号が変化します。ブラケット内を検索できるルートファインダーはここで行います。
fzero(f0,[2,3])
ans =
2.4048
fzero(f0,[5,6])
ans =
5.5201
fzero(f0,[8,9])
ans =
8.6537
符号の変化を探して、既知のブラケットをルート ファインダーに投入します。これにより、ブラケットを見つけることができる限り多くのソリューションが得られます。
上記のスキームには重大な問題があることに注意してください。符号の変化が存在しないため、f(x)=x^2 のような単純な関数の二重根を見つけることは完全に失敗します。また、選択したサンプリングが粗すぎると、その中に 2 つの根がある間隔ができますが、終点での符号の変化は見られません。
たとえば、関数 f(x) = x^2-x を考えてみます。この関数は 0 と 1 で単一根を持ちます。しかし、その関数を -1 と 2 でサンプリングすると、両方の点で正であることがわかります。符号の変化はありませんが、2 つのルートがあります。
繰り返しますが、完璧にできる方法はありません。そのような数値メソッドが失敗する原因となる関数をいつでも考案できます。