goo*_*ion 6 c optimization performance logarithm fixed-point
我正在开发一个定点平台(不支持浮点运算).
我将任何有理数表示q为q * (1 << precision).
我需要用于计算对数底2的有效方法x,其中1 < x < 2.
这是我到目前为止所做的:
uint64_t Log2(uint64_t x, uint8_t precision)
{
uint64 res = 0;
uint64 one = (uint64_t)1 << precision;
uint64 two = (uint64_t)2 << precision;
for (uint8_t i = precision; i > 0 ; i--)
{
x = (x * x) / one; // now 1 < x < 4
if (x >= two)
{
x >>= 1; // now 1 < x < 2
res += (uint64_t)1 << (i - 1);
}
}
return res;
}
Run Code Online (Sandbox Code Playgroud)
这很好用,但它会影响我的程序的整体性能,这需要为大量的输入值执行此操作.
尽管如此,precision使用的是31,但这可能会改变,所以我需要将它保留为变量.
我可以在这里应用任何优化吗?
我想的是"先乘,最后总结"的形式.
但这意味着计算x ^ (2 ^ precision),这将很快溢出.
谢谢.
更新:
我之前试图摆脱分支,但它只是让事情变得更糟:
for (uint8_t i = precision; i > 0 ; i--)
{
x = (x * x) / one; // now 1 < x < 4
uint64_t n = x / two;
x >>= n; // now 1 < x < 2
res += n << (i - 1);
}
return res;
Run Code Online (Sandbox Code Playgroud)
我唯一能想到的就是用右移而不是递减来执行循环,并将一些操作更改为其等效的二进制操作。这可能与您的平台相关,也可能无关,但在我的 x64 PC 中,它们产生了约 2% 的改进:
uint64_t Log2(uint64_t x, uint8_t precision)
{
uint64_t res = 0;
uint64_t two = (uint64_t)2 << precision;
for (uint64_t b = (uint64_t)1 << (precision - 1); b; b >>= 1)
{
x = (x * x) >> precision; // now 1 < x < 4
if (x & two)
{
x >>= 1; // now 1 < x < 2
res |= b;
}
}
return res;
}
Run Code Online (Sandbox Code Playgroud)