是否有更好的MACRO来获得2 ^ n的恒定功率值(1 <n)

时间:2014-12-03 12:52:31

标签: c macros

我需要获得一些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标准库。

2 个答案:

答案 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())并查看编译器的作用,它很可能在编译时解决它。