基本上,我试图使用下面代码中计算的值,但是当我将值存储在所有具有自己速率的对象中时,正在添加足够的字节以导致缓存未命中。使用查找表显然无济于事。
所以我正在寻找一种比标准功率函数更快获得这些值的方法,由于可能的输入非常有限,我可以使用任何技巧吗?
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);
}
答案 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];