Oli*_*ver 3 algorithm optimization logarithm lookup-tables
我正在尝试优化一个音频算法,该算法必须在每个步骤中计算两种算法,如下所示。现在我已经读到,没有对数在多项式时间内运行的算法。我的问题是,通过查找表对所有对数进行运算是否有意义,因为它们总是相同的,尽管这样做有大量内存访问的缺点?
for(int f=1;f<11000;f++){
for(int fk=1;fk<1000;fk++){
int k = ceil(12 * log2f((f - 0.5) / fk));
}
}
Run Code Online (Sandbox Code Playgroud)
我在用C ++编程。
非常感谢!
如果您真正需要的是
ceil(12 * log2(/* something */))
Run Code Online (Sandbox Code Playgroud)
那么只有一个仅包含12个值的表,它会非常简单地进行O(1)计算。
使用frexp()将值分为指数和尾数。(这只是一点点操作,因此只需要几个周期。)
在预先计算的2.0的第12个根的幂(除以2)的列表中查找尾数,最多可以进行四个比较。
结果是12 *(指数-1)+最小根的索引> =尾数。
编辑添加:
实际上,还有一个更好的解决方案,因为两个的12的根的幂被合理地平均分配。如果将[0.5,1.0)(frexp返回的尾数范围)划分为17个等距的子范围,则每个子范围将属于两个可能的返回值之一。因此,如果将每个带有索引的子范围与根向量相关联,则只需将目标(在该范围内)与单个根进行比较。
对我来说,写出连贯的英语为时已晚,因此您必须满足以下条件:
int Ceil12TimesLog2(double x) {
int exp;
double mantissa = std::frexp(x, &exp) * 2;
int idx = indexes[int((mantissa - 1.0) * 17)];
return 12 * (exp - 1) + (mantissa <= roots[idx] ? idx : idx + 1);
}
// Here are the reference tables.
double roots[12] = {
0x1.0000000000000p+0,
0x1.0f38f92d97963p+0,
0x1.1f59ac3c7d6c0p+0,
0x1.306fe0a31b715p+0,
0x1.428a2f98d728bp+0,
0x1.55b8108f0ec5ep+0,
0x1.6a09e667f3bccp+0,
0x1.7f910d768cfb0p+0,
0x1.965fea53d6e3dp+0,
0x1.ae89f995ad3adp+0,
0x1.c823e074ec129p+0,
0x1.e3437e7101344p+0
};
int indexes[17] = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11 };
Run Code Online (Sandbox Code Playgroud)
我尝试了这一点,使用OP中的循环将总计算时间从大约0.5秒(对于log2f)降低到大约0.15秒。参考表的总大小为164字节。