c - 带 float 指数的 2 的快速幂 [C]

标签 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);
}

最佳答案

采取这一行:

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 的指数,但这将不可移植。

编辑:正如 user3386109 在评论中指出的那样,如果您打开优化,编译器可能会为您优化 2 的整数次方,因此此代码可能会更快:

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

关于c - 带 float 指数的 2 的快速幂 [C],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38680065/

相关文章:

c - 将字符串转换为 double 后返回值不正确?

c++ - 从陀螺仪+加速度计数据计算四元数

python - 我怎样才能让我的程序打印 float ?

perl - 为什么 'print (52-80)*42' 与 Perl 中的 'print 42*(52-80)' 不同?

math - 在 Elixir 中使 float 变圆的最佳方法是什么

c - 需要知道 fork 是如何工作的吗?

c - 需要随机数的猜谜游戏帮助

c - 如何控制互斥量的加锁和解锁?

c - 多线程如何选择-c

javascript - 将缓动纳入基于时间的移动