多项式: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);
但我想知道是否有更好的方法来计算这个多项式?
**对于任何人都认为这是一个不同的计算:我测试了上面的功能。它与y += array_a[index] * Math.Pow(x, index);
做同样的事情,他们计算相同的结果。
感谢。
答案 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使其自动化速度非常快。无论如何,对于这种微优化,总是在提交最终解决方案之前进行概述。