我需要获得一些2的幂的常数。 为了优化运行时间,我采用MACRO在编译阶段获得这些功能。 (8-> 3,16-> 4,32-> 5 ......等)
从“黑客的喜悦”一书中,我找到了一个有用的功能,可以找到2 ^ n的幂,即计数1位。问题变成计数(2 ^ n - 1)的1位。 例如,2 ^ 8-1是255,其中8个1位,8是256的幂。 以下是计算32位变量的1位的表达式。
x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
x = (x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF);
所以我在MACRO中展开这五个表达式,得到一个常数N的幂,即2的幂。这很有用,但不是说非常繁琐。
N is an power of two constant value, and let x = N - 1
#define mGET_POWER_OF_2S_VALUE(x) ( (((((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) & 0x0F0F0F0F) + ((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) >> 4) & 0x0F0F0F0F)) & 0x00FF00FF) + ((((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) & 0x0F0F0F0F) + ((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) >> 4) & 0x0F0F0F0F)) >> 8) & 0x00FF00FF)) & 0x0000FFFF) + ((((((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) & 0x0F0F0F0F) + ((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) >> 4) & 0x0F0F0F0F)) & 0x00FF00FF) + ((((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) & 0x0F0F0F0F) + ((( ((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) & 0x33333333) + (((((x) & 0x55555555) + (((x) >> 1) & 0x55555555)) >> 2) & 0x33333333)) >> 4) & 0x0F0F0F0F)) >> 8) & 0x00FF00FF)) >>16) & 0x0000FFFF) )
P.S。我的平台是嵌入式系统,在编码过程中没有任何C标准库。
答案 0 :(得分:1)
使用一些辅助宏,你可以让你的宏不那么怪异了:
#define x1(x) (x & 0x55555555) + (x>> 1 & 0x55555555)
#define x2(x) (x & 0x33333333) + (x>> 2 & 0x33333333)
#define x3(x) (x & 0x0F0F0F0F) + (x>> 4 & 0x0F0F0F0F)
#define x4(x) (x & 0x00FF00FF) + (x>> 8 & 0x00FF00FF)
#define x5(x) (x & 0x0000FFFF) + (x>>16 & 0x0000FFFF)
#define mGET_POWER_OF_2S_VALUE(x) x5(x4(x3(x2(x1(x)))))
另一种方式(也可以在编译时为给定的N = 2 0..32 计算)是这样的:
#define P(i) 1U<<i?i:
#define LB(N) N&P(0)N&P(1)N&P(2)N&P(3)N&P(4)N&P(5)N&P(6)N&P(7)N&P(8)N&P(9)\
N&P(10)N&P(11)N&P(12)N&P(13)N&P(14)N&P(15)N&P(16)N&P(17)N&P(18)\
N&P(19)N&P(20)N&P(21)N&P(22)N&P(23)N&P(24)N&P(25)N&P(26)N&P(27)\
N&P(28)N&P(29)N&P(30)N&P(31)32
顺便说一下,这个宏LB()
也会产生值为1..0x1FFFFFFFF的最低设置位的索引。
答案 1 :(得分:0)
如果值是常量,我不明白为什么你需要在运行时计算它。最好使用最简单的表达式(甚至可能使用log()
)并查看编译器的作用,它很可能在编译时解决它。