查找多项式的实根


24

编写一个自包含的程序,当给定一个多项式和一个界限时,它将发现该多项式的所有实根都达到不超过界限的绝对误差。

约束条件

我知道Mathematica以及其他一些语言都有一个符号解决方案,这很无聊,因此您应该坚持原始操作(加,减,乘,除)。

输入和输出格式具有一定的灵活性。您可以通过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)

注意:此问题在沙盒中存在大约3个月。如果您认为需要在发布之前进行改进,请访问“沙箱”并在其他建议的问题发布到Main之前对其进行评论



@belisarius,??
彼得·泰勒

3
原本是个玩笑:(
belisarius博士13年

我知道这是一个古老的挑战,因此,如果您不想重新打开它,就不必回答。(a)我们可以编写函数还是仅编写完整程序?(b)如果我们可以编写一个函数,是否可以假设输入使用某种方便的数据类型,例如Python的fractions.Fraction(有理数类型)?(c)我们是否必须处理小于1的多项式?(d)我们可以假设超前系数为1吗?
2015年

(e)对于具有重复根的多项式,有必要在奇数和偶数乘法的根之间进行区分(测试案例仅具有奇数乘法的根。)虽然奇数多重性的根并不难处理,我不知道正确地数值处理偶数根的有多切实,尤其是因为您只为根的值指定了误差余量,而不是它们的存在。(...)
Ell 2015年

Answers:


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&]]

该解决方案实现了用于求解多项式的Durand-Kerner方法。请注意,这不是一个完整的解决方案(如下所示),因为我还无法将Wilkinson的多项式处理到指定的精度。首先解释一下我在做什么: Mathematica格式的代码

#[[i]]-p[#[[i]]]/Product[If[i!=j,#[[i]]-#[[j]],1],{j,l}]&:因此,函数将为每个索引计算i下一个Durand-Kerner近似值。然后,将此行封装在表格中,并使用NestWhile将其应用于生成的输入点Table[(0.9+0.1*I)^i,{i,l}]。NestWhile的条件是,从一次迭代到下一次迭代的最大变化(在所有条件下)都大于指定的精度。当所有项的变化均小于此值时,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.}

如您所见,当度数越高时,此方法就开始围绕正确的值反弹,从不真正地完全归位。如果我将代码的停止条件设置为比“从一次迭代到下一次猜测的改变最多不超过epsilon”严格,则该算法永远不会停止。我想我应该将Durand-Kerner用作牛顿方法的输入?


杜兰德·克纳(Durand-Kerner)也有多重根源的潜在问题。(牛顿方法也可能无济于事-威尔金森多项式被特别选择为病态的)。
彼得·泰勒

您是完全正确的:我放大了威尔金森(Wilkinson)在x = 17附近的位置,这是绝对的混乱。我担心我将不得不以Groebner为基础寻求一种符号解决方案,以获取更高的准确性。
卡亚
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.