计算多项式的最有效方法

时间:2016-08-30 15:13:10

标签: java polynomial-math

多项式:a0x ^ 0 + a1x ^ 1 + a2x ^ 2 + a3x ^ 3 + ... + anx ^ n

数组:array_a [] = {a0,a1,a2,a3 ... an};

我写了一个用Java来计算这个多项式的函数:

public double cal(double x) {
    double y = 0.0;
    for (int index = array_a.length - 1; index >= 0; index--) {
        y = array_a[index] + y * x;
    }
    return y;
}

这似乎比循环y += array_a[index] * Math.Pow(x, index);

快5倍

但我想知道是否有更好的方法来计算这个多项式?

**对于任何人都认为这是一个不同的计算:我测试了上面的功能。它与y += array_a[index] * Math.Pow(x, index);做同样的事情,他们计算相同的结果。

感谢。

1 个答案:

答案 0 :(得分:5)

这是霍纳的方法。如果您只想按每个多项式计算一次,this is the most efficient algorithm

  

... Horner的方法仅需要 n 添加和 n 乘法,其存储要求仅为 n 次数 x 的位。 ...

     

Horner的方法是最优的,因为评估任意多项式的任何算法必须至少使用尽可能多的操作。亚历山大·奥斯特罗夫斯基(Alexander Ostrowski)在1954年证明,所需的增加数量很少。 Victor Pan在1966年证明了乘法的次数很少。

如果需要多次求多项式并且度数非常高,那么有一些方法可以转换多项式的表示(预处理),以便乘法的数量减少到⌊ n /2⌋+ 2.这似乎不太实用,至少我从来没有在野外看过这个。 I've found an online paper that describes some of the algorithms if you are interested

本文还提到,由于采用CPU架构,如果单独评估偶数和奇数项可能会更有效,因此可以将它们放在并行流水线中:

public double cal(double x) {
    double x2 = x * x;
    double y_odd = 0.0, y_even = 0.0;
    int index = array_a.length - 1;
    if (index % 2 == 0) {
        y_even = array_a[index];
        index -= 1;
    }
    for (; index >= 0; index -= 2) {
        y_odd = array_a[index] + y_odd * x2;
        y_even = array_a[index-1] + y_even * x2;
    }
    return y_even + y_odd * x;
}

JIT /编译器可能能够为您执行此转换,甚至可以使用SIMD使其自动化速度非常快。无论如何,对于这种微优化,总是在提交最终解决方案之前进行概述。