Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 闭式多项式求根算法_C++_Numeric_Polynomials - Fatal编程技术网

C++ 闭式多项式求根算法

C++ 闭式多项式求根算法,c++,numeric,polynomials,C++,Numeric,Polynomials,我正在寻找一种稳健的算法(或一篇描述算法的论文),该算法可以使用封闭形式的解决方案找到多项式的根(理想情况下,直到第四个debree,但任何方法都可以)。我只对真正的根感兴趣 我对求解二次方程的第一个理解涉及到这一点(我也有类似风格的三次/四次方代码,但现在让我们关注二次方): 请注意,该精度与系数的大小有关,通常在10^6范围内(因此最终精度远未达到完美,但可能大部分可用)。然而,如果没有门槛,它几乎是无用的 我曾尝试使用多精度算法,通常效果很好,但往往会拒绝许多根,因为多项式的系数不是多精度

我正在寻找一种稳健的算法(或一篇描述算法的论文),该算法可以使用封闭形式的解决方案找到多项式的根(理想情况下,直到第四个debree,但任何方法都可以)。我只对真正的根感兴趣

我对求解二次方程的第一个理解涉及到这一点(我也有类似风格的三次/四次方代码,但现在让我们关注二次方):

请注意,该精度与系数的大小有关,通常在10^6范围内(因此最终精度远未达到完美,但可能大部分可用)。然而,如果没有门槛,它几乎是无用的

我曾尝试使用多精度算法,通常效果很好,但往往会拒绝许多根,因为多项式的系数不是多精度的,并且一些多项式无法精确表示(如果二次多项式中有一个双根,它通常会将其拆分为两个根)(我不介意)或者说根本就没有根)。如果我想恢复甚至稍微不精确的根,我的代码会变得复杂,并且充满了阈值

到目前为止,我已经尝试过使用CCmath,但要么我不能正确使用它,要么精度非常差。此外,它在
plrt()
中使用迭代(非闭合形式)解算器

我曾尝试使用GNU科学库
gsl\u poly\u solve\u quadratic()
,但这似乎是一种幼稚的方法,而且在数值上不太稳定

天真地使用
std::complex
数字也被证明是一个非常糟糕的主意,因为精度和速度都可能很差(特别是对于三次/四次方程,其中代码包含大量超越函数)


将根恢复为复数是唯一的方法吗?这样就不会遗漏根,用户可以选择根的精度(从而忽略精度较低的根中的小虚部).

这并不是真的回答你的问题,但我认为你可以改进你所得到的,因为当
b^2>>ac
时,你现在有一个“失去意义”的问题。在这种情况下,你最终得到的公式是
(-b+(b+eps))/(2*a)
其中取消b会从eps中损失许多有效数字

正确的处理方法是对一个根使用平方根的“正常”方程,对另一个根使用鲜为人知的“替代”或“颠倒”方程。采取哪种方法取决于
\u b
的符号

按照以下几行对代码进行更改应该可以减少由此产生的错误

if( _b > 0 ) {
    p_real_root[i] = T((-_b - f_disc) / (2 * _a));
    p_real_root[1 - i] = T((2 * _c) / (-_b - f_disc));
}
else{
    p_real_root[i] = T((2 * _c) / (-_b + f_disc));
    p_real_root[1 - i] = T((-_b + f_disc) / (2 * _a));
}

在学校,我们用拜尔斯托的方法来求根,也许这是你需要的…@Ikses拜尔斯托你提出的方法很有趣(谢谢),但它用的是牛顿的方法,不是封闭形式。对不起!我的英语不够好,无法理解什么是“封闭形式”@Ikses没有问题。封闭形式是一个可以在有限的步骤中计算的表达式,这通常不能说是牛顿方法,因为它可能根本不会收敛。另一方面,我发布的代码是封闭形式的,因为它甚至不循环,因此总是在固定的步骤中完成。这实际上是退出e有趣。我不太确定它会有什么不同,不过,因为计算
-b-b-eps
会产生大致
-2b
eps
也是一样的四舍五入。需要对此进行测试。这实际上工作起来很奇怪。它会稍微减少找到的根中函数的值,但会增加距离从我期望的地方找到的根的ce(这可能是因为从
(x-r0)(x-r1)
ax^2+bx+c
会失去精度,并且结果的根与预期的根略有不同)。绝对有趣。实际上,这非常好!我刚刚实现了中描述的测试套件,它总是返回54位有效位的根。我需要放弃我一直使用的测试套件。做得好。
root response precision 1e-100: 6315 cases
root response precision 1e-19: 2 cases
root response precision 1e-17: 2 cases
root response precision 1e-16: 6 cases
root response precision 1e-15: 6333 cases
root response precision 1e-14: 3765 cases
root response precision 1e-13: 241 cases
root response precision 1e-12: 3 cases
2-root solution precision 1e-100: 5353 cases
2-root solution precision 1e-19: 656 cases
2-root solution precision 1e-18: 4481 cases
2-root solution precision 1e-17: 2312 cases
2-root solution precision 1e-16: 455 cases
2-root solution precision 1e-15: 68 cases
2-root solution precision 1e-14: 7 cases
2-root solution precision 1e-13: 2 cases
1-root solution precision 1e-100: 3022 cases
1-root solution precision 1e-19: 38 cases
1-root solution precision 1e-18: 197 cases
1-root solution precision 1e-17: 68 cases
1-root solution precision 1e-16: 7 cases
1-root solution precision 1e-15: 1 cases
if( _b > 0 ) {
    p_real_root[i] = T((-_b - f_disc) / (2 * _a));
    p_real_root[1 - i] = T((2 * _c) / (-_b - f_disc));
}
else{
    p_real_root[i] = T((2 * _c) / (-_b + f_disc));
    p_real_root[1 - i] = T((-_b + f_disc) / (2 * _a));
}