具有浮动指数的两个快速幂[C]

时间:2016-07-31 01:53:36

标签: c math

基本上,我试图使用下面代码中计算的值,但是当我将值存储在所有具有自己速率的对象中时,正在添加足够的字节以导致缓存未命中。使用查找表显然无济于事。

所以我正在寻找一种比标准功率函数更快获得这些值的方法,由于可能的输入非常有限,我可以使用任何技巧吗?

static inline
double __attribute(( pure )) get_decay_rate(uint8_t rate)
{
     if(rate >= 128)
     {
          return 65535.0/65536.0;
     }

     double k = pow(2, rate/8.0);
     return (k - 1.0) / k;
}


/* pseudocode:
     double k = (int) pow(2, k/8.0);
     k = (k - 1) / k;
     return log(65535/65536)/log(k);
*/
static inline
uint16_t __attribute(( pure )) get_decay_modulus(uint8_t rate)
{
     if(rate <= 128)
     {
          return 1;
     }
//turns out to be the same as the above pseudocode, for some reason. 
     return pow(2, (rate - 128) / 8.0);
}

1 个答案:

答案 0 :(得分:2)

采取这一行:

double k = pow(2, rate/8.0);

基本上你在这里做的是将2提高到固定点数的功率。

你可以利用pow(a,b + c)= pow(a,b)* pow(a,c)和非整数=整数部分+小数部分这一事实。因此,您使用固定点数的整数部分计算pow,并将其与小数部分的pow相乘。

将8个小数指数存储在查找表中:

double fractionalPowersOf2[8];

for(int i = 0; i < 8; i++)
    fractionalPowersOf2[i] = pow(2.0, i / 8.0);

然后你可以像这样进行计算:

double k = (double)(1 << (rate >> 3)) * fractionalPowersOf2[rate & 7];

这会屏蔽小数部分并将其用于表查找,然后使用位移将乘以2提升到整数部分的幂。如果转换为double的速度太慢,您也可以使用查找表。

你也可以使用一些花哨的bitmagic类型方法,你可以通过转换指针等将你的值用作double的指数,但这不是可移植的。

编辑:正如用户3386109在注释中指出的那样,如果启用优化,编译器可能会优先将2提升为整数值的幂,因此此代码可能更快:

 double k = pow(2,rate>>3) * table[rate&7];