[英]Could someone help explain what this C one liner does?
我通常可以弄清楚大多数C代码,但这是我的头。
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
用法示例如下:
int x = 57;
kroundup32(x);
//x is now 64
其他一些示例是:
一对一
2比2
7至8
31至32
60至64
3000至4096
我知道它会将一个整数四舍五入为最接近的2的幂,但是据我所知,这是差不多的。
任何解释将不胜感激。
谢谢
(--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
对于32位无符号整数,这应将值向上移动到等于或大于2的最接近的幂。 “或”部分将所有低位设置在最高位以下,因此它的最终幂为2减1,然后再加一个。 看起来似乎已经过优化,因此不太可读; 可以通过按位操作和位移位单独进行操作,也可以作为宏进行操作(因此无需调用函数)。
按位或和移位操作实质上是将最高位和零位之间的每个位设置。 这将产生2^n - 1
形式的数字。 最后的增量加1得到2^n
形式的数字。 初始递减可确保您不会将已经是2的幂的数字四舍五入到下一个幂,例如2048不会变成4096。
在我的机器上, kroundup32
提供了6.000m发/秒
下一个功能给出7.693m发/秒
inline int scan_msb(int x)
{
#if defined(__i386__) || defined(__x86_64__)
int y;
__asm__("bsr %1, %0"
: "=r" (y)
: "r" (x)
: "flags"); /* ZF */
return y;
#else
#error "Implement me for your platform"
#endif
}
inline int roundup32(int x)
{
if (x == 0) return x;
else {
const int bit = scan_msb(x);
const int mask = ~((~0) << bit);
if (x & mask) return (1 << (bit+1));
else return (1 << bit);
}
}
因此,@ thomasrutter我不会说它是“高度优化的”。
和适当的(仅有意义的部分)组装(对于GCC 4.4.4):
kroundup32:
subl $1, %edi
movl %edi, %eax
sarl %eax
orl %edi, %eax
movl %eax, %edx
sarl $2, %edx
orl %eax, %edx
movl %edx, %eax
sarl $4, %eax
orl %edx, %eax
movl %eax, %edx
sarl $8, %edx
orl %eax, %edx
movl %edx, %eax
sarl $16, %eax
orl %edx, %eax
addl $1, %eax
ret
roundup32:
testl %edi, %edi
movl %edi, %eax
je .L6
movl $-1, %edx
bsr %edi, %ecx
sall %cl, %edx
notl %edx
testl %edi, %edx
jne .L10
movl $1, %eax
sall %cl, %eax
.L6:
rep
ret
.L10:
addl $1, %ecx
movl $1, %eax
sall %cl, %eax
ret
由于某种原因,我没有在GCC的标准标头(仅__TBB_machine_lg
/ __TBB_Log2
)中找到适当的scan_msb
实现(例如#define scan_msb(x) if (__builtin_constant_p (x)) ...
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.