试图为Hermite多项式强制根源

时间:2012-04-22 16:19:48

标签: c math runtime

我有一个程序应该通过使用牛顿方法找到第**个hermite多项式的根,但是运行程序需要很长时间。我对C很陌生,所以我无法弄清楚我的bug在哪里,或者这只是暴力迫使这个问题的本质。我也遇到了准确根源的问题,但到目前为止,很难找到这个bug,因为我只能每5-10分钟运行一次测试用例

删除代码

1 个答案:

答案 0 :(得分:1)

我100%肯定Newton-Raphson没有充分理由花这么多时间。在某些情况下,它可能会有问题,因为这种方法无法保证收敛。但在你的具体情况下 - 应该没有问题。

有一点很明显,你怪异过度使用递归。只计算你的hermite,其中n = 37是一个递归,其复杂程度与37个Fibonacci数相加,大约 40,000

现在,请认为您的newton方法应该重复调用hermite,以及h_deriv(具有递归幅度的相同数量级),直到收敛为止到10^-12。听起来像几十个互动。

而且,还不够,你还设法实现newton 递归!世界上没有理由这么做。 (lisp / scheme是你的第一种编程语言吗?)

这是您应该采取的措施来改善绩效:

  1. 修复您的hermite。你应该计算37 系数,这可以递归地完成。完成后 - 您应该使用它们来计算正常时间内多项式的值。

  2. 衍生品相同。只需计算36个系数。

  3. 可选择修复您的newton。据我所知 - 你不会获得太多的表现:你的“递归”仍然是一个尴尬的循环。然而,它看起来会更好,并且消耗更少的堆栈。

  4. 修改

    阅读评论后,我花时间尝试建立&跑这个。而且,我必须承认,我低估了问题的复杂性。

    事实证明,由递归关系计算的系数迅速增长,并且舍入误差似乎占主导地位。因此,通过暴力解决这个问题具有不可避免的含义,并且使用预先计算的系数(并以直线顺序求和)并不明显产生相同的结果。

    然而,有一种方法可以在不改变计算逻辑的情况下摆脱荒谬的递归:

    const int N = 37;
    
    double g_pHermiteValues[N+1];
    
    void CalcHermiteAt(double x)
    {
        double x2 = x*2;
    
        g_pHermiteValues[0] = 1.;
        g_pHermiteValues[1] = x2;
    
        for (int n = 2; n <= N; n++)
            g_pHermiteValues[n] =
                g_pHermiteValues[n - 1] * x2 - 
                g_pHermiteValues[n - 2] * 2*(n - 1);
    }
    
    double CalcHermiteDerivAt()
    {
        return g_pHermiteValues[N - 1] * 2*N;
    }
    
    double newton(double x_0)
    {
        const double tolerance = 1E-12;
    
        while (true)
        {
            CalcHermiteAt(x_0);
    
            if (abs(g_pHermiteValues[N]) < tolerance)
                return x_0;
    
            x_0 -= g_pHermiteValues[N] / CalcHermiteDerivAt();
        }
    }
    

    也就是说,我们使用相同的递归关系。只是为了计算给定点处的Hermite多项式的值,我们为所有多项式计算它,直到n = 37 <强>迭代,并将结果存储在全局数组中。然后它的顶部元素保存所需的结果,并且衍生物也从末尾的第二个数组元素推导出来。

    因为在Newton-Raphson算法的每一步中我们都需要同一点的值和导数 - 这是有效的。

    P.S。但到目前为止我无法找到解决方案。 Newton-Raphson并没有因为我试图开始的点而收敛。

    我相信对于这样的问题,可以使用更稳健的方法,例如中值搜索。