根寻找时的包围算法。 “二次”函数中的单根

时间:2012-10-10 14:43:31

标签: c++ algorithm math

我正在尝试实现根查找算法。我正在使用在数值配方中找到的混合Newton-Raphson算法,该算法运行得非常好。但我把根包围起来有问题。

在实现根查找算法时,我意识到在某些情况下,我的函数有1个真实的根和所有其他的虚数(其中几个,通常是6或9)。我感兴趣的唯一根就是真正的根,所以问题不存在。问题是函数接近根就像一个三次函数,用点y = 0轴接触......

Newton-Rapson方法需要一些不同符号的括号,我发现的所有包围方法都不适用于这种特定情况。

我该怎么办?在我的程序中找到root是非常重要的......

编辑:更多问题:有时由于数据误差很小,比如1e-6的某种变化,“立方”函数不具有那个真实的根,它只是虚构的,具有可忽略的虚部。 ..(用matlab检查)

编辑2:有关此问题的更多信息。

好的,我需要找根算法。

我有信息:

  • 我需要找到的根在[0-1]之间,如果该部分之外还有更多根,我对它们不感兴趣。
  • 根是真实的,可能有想象的根,但我不想要它们。
  • 可能所有其他根源都是假想的
  • 在这一点上根可能是双倍的,但我认为实际上并没有解决数值分析问题
  • 我需要在整体计算过程中多次使用根查找算法,但函数将始终是多项式
  • 在根发现的一个特定情况中,我的多项式将类似于用该点接触Y = 0的二次函数。真实案例: enter image description here
  • 系数可能不是100%精确,真正轻微的不精确可能使功能不接触Y = 0轴。
  • 我无法解决这个具体案例,因为在其他情况下,多项式可能很正常,并且不会产生任何“奇怪”的事情。
  • 我实际使用的方法是NewtonRaphson hybrid,其中如果导数非常小,则会产生二分而不是NewRaph(在数字配方中找到)。

Matlab对图像功能的回答: 根:

0.853553390593276 + 0.353553390593278i
0.853553390593276 - 0.353553390593278i
0.146446609406726 + 0.353553390593273i
0.146446609406726 - 0.353553390593273i
0.499999999999996 + 0.000000040142134i
0.499999999999996 - 0.000000040142134i

这个函数是我准备的一个真实例子,我知道我想要的答案是0.5

注意: 我还没有完全检查一下你们给我的一些答案(谢谢!),我只是想提供我已经掌握的信息来完成这个问题。

6 个答案:

答案 0 :(得分:3)

假设你有一维多项式问题(我从假想的解决方案中假设)你可以使用Sturm序列来包含所有真实的根。请参阅Sturm's theorem

答案 1 :(得分:2)

欢迎来到精彩的数值方法世界。看你的发际线;当你沮丧地拉扯你的头发时,它可能会开始消退。

首先,根据数字根找到,如果你不能解决这个问题,你就会干杯。一旦你靠近,Newton Raphson很适合抛光解决方案,只有当根附近的衍生物远离零时它才有效。你总是需要一些较慢的技术作为备份,因为Newton Raphson可以把你送到永不落地的地方(即在支架之外的某个地方)。如果你的函数不是多项式,首先要尝试的是布伦特的方法。如果您的函数是多项式,请尝试使用Laguerre方法或Jenkins-Traub。

顺便说一下,听起来你有一个病理问题。你不应该期待特别好的表现。病理问题是病态的。

<强>附录
如果您遇到的问题似乎是根源,但事实并非如此,那么您需要注意如何评估您的功能。如果确实有多项式,则形成多项式的每个项,按绝对值排序,并将最小值加到最大值。这在大多数情况下会产生更好的准确性,但如果您的总和几乎为零,则会失败。如果是这种情况,您可能需要单独添加这些取消条款,将剩余的最小值添加到最大值,然后计算总计 - 并且仍然有点傻逼。几乎取消的那个大的增加会失去很多精确度。除了扩展精度算术之外,没有任何其他方法。

答案 2 :(得分:1)

使用Newton-Raphson是一种绝望的行为。你最好找到代表你的功能的连续分数并计算它。 CF会更快地收敛并产生真正的根。此外,因为CF产生两个整数的比率,所以你可以严格控制数字精度,而不必担心舍入误差的积累和其他类似的拔毛问题。

要找到任何多项式函数的真实根,请参阅David Rosen(1978)的“用于逼近所有真实多项式根的连续分数算法”。

------------ ADDENDUM 1 --- 11 OCT -----------------

好的,你正在解决一个问题。你有几个选择。最简单的是结合Halley方法使用泰勒近似(比如3度)。这比牛顿要好得多,因为它具有立方收敛性,你可以检测出虚构的解。缺点是你会有舍入问题,可能导致错误答案。

理想的选择是找到代表monic根的连续分数,因为这个CF可以作为任何所需精度的整数比计算,从而消除了舍入问题。

计算此CF的一种方法是通过Jacobi-Perron算法。见Hendy和Jeans论文:http://www.ams.org/mcom/1981-36-154/S0025-5718-1981-0606514-X/S0025-5718-1981-0606514-X.pdf。本文通过CF近似计算了计算立方根和四次根的精确算法。

请注意,如果sextic可以简化,那么它可以转换为四次和二次:http://elib.mi.sanu.ac.rs/files/journals/tm/21/tm1124.pdf。然后,通过Hendy论文中的算法可以解决四次方。

为sextic生成CF的一般解决方案可以通过Rogers-Ramunajan CF完成。有关方法,请参阅以下文章:http://arxiv.org/pdf/1111.6023v2。这将为任何sextic生成CF.

答案 3 :(得分:1)

好吧,如果你的函数接触零但从未穿过它,你似乎正在寻找最小值(或最大值)。在这种情况下,你最好告诉计算机这样做 - 要么找到导数的根(如果你可以分析计算它),要么使用最小化例程。然后检查最小值的函数值是否“足够接近”为零。

重申其他人已经说过的话:

  • 不要以Newton-Raphson方法开始;从布伦特开始甚至是直截了当的二分法几乎总是更好(假如你可以括根)。
  • 1e-6数量级的“小数值误差”具有不良影响的不稳定性值得研究。直接嫌疑人:混合花车和双打,某处精度不足等。

编辑:那么,根据一些参数,你的函数有零交叉,或者最小零值,这是正确的吗?在这种情况下,我要做的是:使用一个简单而强大的包围策略(例如从[-1, 1]开始,将端点乘以1.1,检查符号,保持乘法,这样的事情) 。如果成功,则存在零交叉,使用根查找例程。如果包围失败,请使用最小化。

答案 4 :(得分:1)

安德,谢谢回答我的问题(关于间隔);抱歉延迟跟进 - 我的工作非常繁忙。另外 - 在我找到你提供的其他信息之前 - 我想到了解释如何处理这个问题的很多事情,并且正在考虑如何呈现它。但是,我现在相信你的情况并不太难,我们可以在没有太多额外的东西的情况下得到它,因为你显然有一个明确的多项式表达式(各种幂的系数)。

让我们从一个简单的案例开始,找出方法。

第1步。 如果你有一个二次多项式,它的导数是一阶的并且有一个简单的零(你可以通过括号或简单地通过明确求解方程找到)。 (是的,我知道二阶多项式的根也是一个封闭的公式,但是为了当前的论证,让我们忘记这一点)。 然后,二阶多项式的零点位于导数零点的一侧,一个位于零点的右侧。因此,如果你还有找到原函数(二次多项式)的根的区间,你现在有两个区间 - 导数零的左边和右边,每个都有一个零。

重要的是要认识到原始函数在每个子区间都是MONOTONIC(在其中一个上减少,在另一个上增加)。因此,只需检查(子)间隔末尾的函数值,即可确定它们是否实际包含零。如果没有,那么多个零(在这种情况下是双精度)恰好在导数的零点处,函数为零(否则,它是一个双虚构的根,你现在已经找到了真实的一部分)。

如果导数的零位于整个区间的外部,则在区间内最多只有一个根,并且您只需要检查该特定(子)区间。

第2步。 现在考虑一个三阶多项式。 它的衍生物是二阶。 THAT二阶多项式的导数又是第一阶,你像以前一样继续得到两个子区间来找到原函数导数的根。这两个根给你三个(最多)间隔,你会发现原始(第三阶)函数的3个根。 而且在这里,你将有间隔(3),其中原始函数是单调的(交替增加/减少),使得每个子区间的分析非常容易。

同样,零可以重合(2或甚至全部3),并且可以另外变成复数值(即具有非零虚部)。对案例的分析很简单:检查区间边界处的函数值,以评估是否存在符号变化(每个子区间上的函数是单调的)和/或在一个子区间中函数是否为零-borders。

第4步。 用已知多项式推广它。让我们说 - 你的例子 - 它是第6顺序:

a)构建第5个导数(即将原始数据减少为1阶多项式)。计算它的零(在你的例子中恰好是0.5)。在这种情况下,您已经完成了,但假设您没有意识到这一点。所以你现在有2个区间0..0.5和0.5..1

b)构建第四衍生物。在子区间边界(0,0.5,1)处检查其值 对于每个子区间,确定其内部是否为真零。如果是这样,你使用找到的两个零(你忘记了5阶导数的零),在3个子区间内重新划分原始区间。如果它们一致(在前一次切割时为0.5),你坚持使用0.5(不要小心你是否已经找到了你的第四个导数的真正双零或者一个&#34;双重想象&#34;并且仍然只有2个间隔,但为了论证,让我们说你现在有3个。

c)构建第三衍生物并像以前一样进行。然后,您将有4个(最多)间隔。

d)依此类推。在以这种方式处理了第二个导数后,你有5个(最多)间隔,并且在处理了1个导数之后你有6个间隔(或更少......)并且知道每个子区间的函数都是单调的,你就可以了在每一个中快速确定是否存在真正的根,并始终使用每个最终子区间中函数的已知单调性。

在评估函数时添加关于数值精度的注释: 第一个(在这种情况下可能是足够的)减少噪声的方法不是以原始形式建议的方式评估你的函数(即a6 x * 6 + a5 x * 5 + ..),但要将其重写为:

a0 + x *(a1 + x *(a2 + x *(a3 + x *(a4 + x *(a5 + x * a6))))))

因此,在评估时,请继续:

tmp = a6

tmp = x * tmp + a5

tmp = x * tmp + a4

等等。

如果这个小的重写不足以满足数值稳定性,你应该在(例如)chebyshev多项式展开中重写多项式,并用它的递归关系来评估那个。两者(获得扩展并应用递归关系进行评估)都相当简单。我可以解释一下,如果你需要帮助,但我想这里没有必要。

在所有情况下,你必须允许一些不准确,即接受一般来说,计算将永远不会给你数学上确切的函数值。因此,评估功能在某些时候是否可能为零必须包括一些“容忍度”,不幸的是,没有办法解决这个问题。你能达到的最好目标是尽量减少噪音。

答案 5 :(得分:1)

与您的情况一样,您对实多项式的实因式分解感兴趣。可能会看到,所有复数根都属于共轭对,它们对应于一个实数二次因子。通过找到该实数二次方并完成平方以得到(x-r)^2 + s的形式,您将能够看到“实数”偶数根r,其中包含s给出的“错误”。如果s > 0过大,则可能会因为复杂而将其丢弃。如果s < 0也很大,则您有两个x = r ± √(-s)给出的远方根。如果s很小,那么您可能会怀疑r是真正的双根并保留它。

可以使用Bairstow's method完成查找这样的二次因子,该方法实际上应用了二维牛顿法。这给出了x^2 + ux + vr = -u/2; s = v - r^2