如何解决在评估多项式时,跳过0系数的有效方法是什么? 您一定可以通过研究此主题获得博士学位
我正在研究具有单核的微芯片(stm32f103c8t6),并且我想评估一些多项式直到预定指数,所以f(x) = a0 + a1*x +a2*x^2 +...+an*x^n
其中 n 在编译时是已知的时间。
系数 a0 ... an 在运行时会发生变化,其中一些极有可能变为零,我想找到一种在评估 f(x )。注意,大多数将为非零。理想情况下,我想在运行时重写 f(x),以便零系数不再存在于函数中,但我不想进入自我修改的代码领域(除非有一些简单的方法C ++的方法)。该微芯片具有单指令乘法的能力,因此任何等效于让if语句检查系数是否为零的解决方案,都将比仅对整个表达式求值相同或更慢。
评估将发生很多次,因此,即使在评估功能时节省一个周期也是有帮助的。目前,我还没有一个可行的解决方案,我只是在整体上评估多项式。
我正在用C ++编写微芯片,尽管我目前正在python中工作,因为这样可以更容易绘制结果,因此我没有任何代码可以解决这个问题。
解决方法
作为第一步,请回想一下,通常用比通常的表示方式更好的方法来计算多项式:
polynomial = a0 + a1*x + a2*x^2 + a3*x^3 + a4*x^4 + a5*x^5 + ...
= a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + ... )...)
= (a0 + x*a1) + x^2*(a2 + x*a3) + x^4*((a4 + x*a5) + x^2*(a6 + x*a7)) + ...
第一行是常规演示,并且存在最终可能滥用动态范围的问题。
第二行倾向于避免计算x的连续幂的数值问题,这是一种实际计算多项式的相当传统的方法。不幸的是,它仍然有很长的依赖关系,这限制了您可以从中获得的指令级并行性。
第三行避免了长的依赖关系,如果有向量单元,它也非常适合利用向量单元。
从您的评论讨论中看来,您正在使用低功率嵌入式处理器。因此,让我们假设没有向量处理器,而且无论如何也没有太多可用的ILP,并改写第二行。 (我将用浮点数来表示,但是它应该很容易适应定点)。
首先,这是一种直接方法,无需尝试跳过零系数:
int max_idx = a.size() - 1;
float result = a[max_idx];
int i = max_idx;
while (i > 0) {
-- i;
result = a[i] + x * result;
}
return result;
现在,这是一个聪明的方法:假设您的系数是固定的,则可以对其进行预处理,以确定可以跳过的x
的幂,因此需要计算哪些增量幂(提前一次) :
// compute powers between nonzero coefficients
int max_idx = a.size() - 1;
assert(a[max_idx] != 0); // you should not have leading zeroes in the first place
std::vector<int> inc_powers;
std::vector<int> inc_indices;
int inc_pow = 0;
int i = max_idx;
while (i > 0) {
-- i;
++ inc_pow;
if (a[i] != 0 || i == 0) {
inc_powers.push_back(inc_pow);
inc_indices.push_back(i);
inc_pow = 0;
}
}
要评估多项式:
int i = a.size() - 1;
float result = a[i];
for (int i = 0; i < inc_powers.size(); ++i) {
result = a[inc_indices[i]] + x_powers[inc_powers[i]] * result;
}
return result;
您将需要计算x_powers
-在上述多项式计算中使用的x的幂的数组。可能有一些聪明的方法可以计算和指定一个最小的计算量,以精确地生成所需的x的幂,但是以递增的方式生成它们的速度可能差不多快(对于慢速处理器上没有ILP的小多项式)。您将需要(提前一次)确定所需的功率:
int max_powers = 0;
for (power: inc_powers) {
if (power > max_powers) { max_powers = power; }
}
std::vector<float> x_powers(max_powers + 1);
然后,对于每次求值,都将它们作为计算多项式值的准备连续进行计算:
float value = x;
for (int i = 1; i < max_powers; ++i) {
x_powers[i] = value;
value *= x;
}
x_powers[max_powers] = value;
(我已经进行了设置,以便未使用x_powers[i] == x^i
和x_powers[0]
。希望这会使操作更容易;当然,实际上,您不必那样做。 )
(以类似的精神,请注意,您可以仅复制非零系数而不使用索引-但这可能更具启发性,所以我将其保留)
最后,由于您担心性能,因此您需要对简单版本和巧妙版本进行实际基准测试,以确保您的“改进”实际上是一种改进。
,相关:Rice's theorem和一些Robinson's theorem。 IIRC您的问题是undecidable或至少是intractable,并且与P versus NP problem有关。尝试使用REDUCE。
请注意,Artificial Intelligence可能是一个更好的询问场所
您可以尝试abstract interpretation和partial evaluation技术
您一定可以通过研究此主题获得博士学位。
研究GCC,MILEPOST GCC和Clang static analyzer的源代码。两者都在做compiler optimizations(或多或少的成功)。考虑也使用Frama-C。
我确定这个问题已经解决了,但是我找不到
据我所知,您的问题没有确切的解决方法
如果找到一个,则会得到Turing award。
阅读J.Pitrat的Artificial Beings: the Conscience of a Conscious Machine(ISBN 978-1848211018)书。它可以为您的问题提供有用的见识。
,使用有限状态机。您需要为每种可能的状态编写代码。但这可能是最快的计算方法。
这是一个示例,它使用示例数学函数和示例迭代值。 OP必须为每个状态提供自己的数学函数和迭代值。
#include <iostream>
int main(int argc,char *argv[]){
/* MAX_COEFFICIENTS <-- states == 2^coefficients */
const int MAX_COEFFICIENTS = 3;
int coefficientsv[] = {1,3}; /* {A,B,C} */
int coefficientsc = sizeof coefficientsv / sizeof coefficientsv[0];
if(coefficientsc > MAX_COEFFICIENTS) return -1; /* Out of bounds! */
register int A = 0,B = 0,C = 0;
for(int i = 0; i < coefficientsc; i++){
if(i == 0) A = coefficientsv[i];
else if(i == 1) B = coefficientsv[i];
else if(i == 2) C = coefficientsv[i];
}
register long polycalc = 0; /* or use just int,if int is big enough */
register int iteration = 1000; /* example value */
/* state truth table */
/* A B C */
/* 0 0 0 goto STATE_0 */
/* 1 0 0 goto STATE_A */
/* 0 1 0 goto STATE_B */
/* 1 1 0 goto STATE_AB */
/* 0 0 1 goto STATE_C */
/* 1 0 1 goto STATE_AC */
/* 0 1 1 goto STATE_BC */
/* 1 1 1 goto STATE_ABC */
STATE_SELECT:
if(!A && !B && !C) goto STATE_0;
if( A && !B && !C) goto STATE_A;
if(!A && B && !C) goto STATE_B;
if( A && B && !C) goto STATE_AB;
if(!A && !B && C) goto STATE_C;
if( A && !B && C) goto STATE_AC;
if(!A && B && C) goto STATE_BC;
if( A && B && C) goto STATE_ABC;
STATE_0:
while(iteration){
polycalc = 0;
iteration--;
}
goto END;
STATE_A:
while(iteration){
polycalc = A;
iteration--;
}
goto END;
STATE_B:
while(iteration){
polycalc = B * B;
iteration--;
}
goto END;
STATE_AB:
while(iteration){
polycalc = A + B * B;;
iteration--;
}
goto END;
STATE_C:
while(iteration){
polycalc = C * C * C;
iteration--;
}
goto END;
STATE_AC:
while(iteration){
polycalc = A + C * C * C;
iteration--;
}
goto END;
STATE_BC:
while(iteration){
polycalc = B * B + C * C * C;
iteration--;
}
goto END;
STATE_ABC:
while(iteration){
polycalc = A + B * B + C * C * C;
iteration--;
}
/* Example: Pseudo-Code */
/* Maybe your first calculation has shown that C becomes 0. */
/* So simply use "goto STATE_AB",maybe set some variables. */
/* In another example,you only know that some coefficient */
/* has become 0,but you don't know which one,*/
/* so use "goto STATE_SELECT",maybe set some variables too. */
goto END;
END:
std::cout << polycalc << std::endl;
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。