在评估多项式时,跳过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^ix_powers[0]。希望这会使操作更容易;当然,实际上,您不必那样做。 )

(以类似的精神,请注意,您可以仅复制非零系数而不使用索引-但这可能更具启发性,所以我将其保留)


最后,由于您担心性能,因此您需要对简单版本和巧妙版本进行实际基准测试,以确保您的“改进”实际上是一种改进。

,

相关:Rice's theorem和一些Robinson's theorem。 IIRC您的问题是undecidable或至少是intractable,并且与P versus NP problem有关。尝试使用REDUCE

请注意,Artificial Intelligence可能是一个更好的询问场所

您可以尝试abstract interpretationpartial evaluation技术

您一定可以通过研究此主题获得博士学位。

研究GCCMILEPOST GCCClang 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;
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...