多項式の実根を見つける


24

多項式と境界が与えられたときに、その多項式のすべての実根を、境界を超えない絶対誤差まで見つける自己完結型プログラムを作成します。

制約

Mathematicaとおそらく他のいくつかの言語には1シンボルのソリューションがあり、それはつまらないことを知っているので、基本的な操作(加算、減算、乗算、除算)に固執する必要があります。

入力および出力形式には一定の柔軟性があります。任意の妥当な形式で、stdinまたはコマンドライン引数を介して入力を受け取ることができます。浮動小数点を許可するか、有理数の表現を使用する必要がある場合があります。バウンドまたはバウンドの逆数を取ることができ、浮動小数点を使用している場合は、バウンドが2 ulp未満ではないと想定できます。多項式は、単項係数のリストとして表現する必要がありますが、ビッグエンディアンまたはリトルエンディアンの可能性があります。

プログラムが常に機能する理由を正当化できる必要があります(モジュロ数値の問題)。ただし、完全な証明をインラインで提供する必要はありません。

プログラムは、根が繰り返される多項式を処理する必要があります。

x^2 - 2 = 0 (error bound 0.01)

入力は例えば

-2 0 1 0.01
100 1 0 -2
1/100 ; x^2-2

出力は例えば

-1.41 1.42

だがしかし

-1.40 1.40

約0.014の絶対誤差があるため...

テストケース

シンプル:

x^2 - 2 = 0 (error bound 0.01)

x^4 + 0.81 x^2 - 0.47 x + 0.06 (error bound 10^-6)

複数のルート:

x^4 - 8 x^3 + 18 x^2 - 27 (error bound 10^-6)

ウィルキンソンの多項式:

x^20 - 210 x^19 + 20615 x^18 - 1256850 x^17 + 53327946 x^16 -1672280820 x^15 +
    40171771630 x^14 - 756111184500 x^13 + 11310276995381 x^12 - 135585182899530 x^11 +
    1307535010540395 x^10 - 10142299865511450 x^9 + 63030812099294896 x^8 -
    311333643161390640 x^7 + 1206647803780373360 x^6 -3599979517947607200 x^5 +
    8037811822645051776 x^4 - 12870931245150988800 x^3 + 13803759753640704000 x^2 -
    8752948036761600000 x + 2432902008176640000  (error bound 2^-32)

NBこの質問は、約3か月間Sandboxにありました。投稿する前に改善が必要だと思う場合は、Sandboxにアクセスして、他の提案された質問がMainに投稿されるコメントしてください。



@belisarius、??
ピーターテイラー

3
ジョークとして意図されていた:(
ベリサリウス博士13年

私はこれが古い挑戦であることを知っているので、あなたがそれを再開したいと思わないならば、答える義務を感じないでください。(a)関数、または完全なプログラムのみを記述できますか?(b)関数を書くことができる場合、入力が何らかの便利なデータ型、例えばPython fractions.Fraction(合理的な型)を使用すると仮定できますか?(c)次数<1の多項式を処理する必要がありますか?(d)先行係数が1であると仮定できますか?
2015

(e)繰り返される根を持つ多項式に関して、奇数と偶数の多重度の根を区別する価値があります(テストケースには奇数の多重度の根しかありません)。特に、多重度の根を数値的に正しく処理することの具体性がわからない。特に、その存在についてではなく、根の値に対してのみエラーマージンを指定するためです。(...)
Ell

回答:


8

Mathematica、223

r[p_,t_]:=Module[{l},l=Exponent[p[x],x];Re@Select[NestWhile[Table[#[[i]]-p[#[[i]]]/Product[If[i!=j,#[[i]]-#[[j]],1],{j,l}],{i,l}]&,Table[(0.9+0.1*I)^i,{i,l}],2*Max[Table[Abs[#1[[i]]-#2[[i]]],{i,l}]]>t&,2],Abs[Im[#]]<t^.5&]]

このソリューションは、多項式を解くためのデュラン-カーナー法を実装しています。ウィルキンソンの多項式を指定された精度で処理できないため、これは完全なソリューションではないことに注意してください(以下に示すように)。最初に私がやっていることの説明: 数学フォーマットのコード

#[[i]]-p[#[[i]]]/Product[If[i!=j,#[[i]]-#[[j]],1],{j,l}]&:したがって、関数は各インデックスiに対して次のデュランカーナー近似を計算します。次に、この行はTableにカプセル化され、NestWhileを使用してによって生成された入力ポイントに適用されTable[(0.9+0.1*I)^i,{i,l}]ます。NestWhileの条件は、1つの反復から次の反復への(すべての項にわたる)最大の変化が指定された精度よりも大きいことです。すべての項の変化がこれよりも小さくなると、NestWhileは終了Re@Selectし、実際の線に該当しないゼロを削除します。

出力例:

> p[x_] := x^2 - 2
> r[p, .01]
{1.41421, -1.41421}

> p[x_] := x^4 - 8 x^3 + 18 x^2 - 27
> r[p, 10^-6]
{2.99999, 3., 3.00001, -1.}

> p[x_] := x^20 - 210 x^19 + ... + 2432902008176640000 (Wilkinson's)
> Sort[r[p, 2^-32]]
{1., 2., 3., 4., 5., 6., 7.00001, 7.99994, 9.00018, 10.0002, 11.0007, \
11.9809, 13.0043, 14.0227, 14.9878, 16.0158, 16.9959, 17.9992, \
19.0001, 20.}

ご覧のように、次数が高くなると、この方法は正しい値の周りを跳ね返り始め、実際には完全にホーミングすることはありません。コードの停止条件を「反復から次の推定までのイプシロンだけの変更」より厳しい条件に設定した場合、アルゴリズムは停止しません。ニュートンのメソッドへの入力としてDurand-Kernerを使用する必要があると思いますか?


Durand-Kernerには、複数のルートに関する潜在的な問題もあります。(ニュートンの方法もあまり役に立たないかもしれません-ウィルキンソンの多項式は、悪条件になるように特別に選択されています)。
ピーターテイラー

あなたは非常に正しいです。ウィルキンソンのx = 17付近を拡大した後、その行動を断念しました。これは絶対的な混乱です。精度を上げるために、Groebnerベースのシンボリックソリューションを使用する必要があるのではないかと心配しています。
カヤ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.