我有以下功能设置N个最高位,例如set_n_high(8)== 0xff00000000000000
uint64_t set_n_high(int n)
{
uint64_t v = 0;
int i;
for (i = 63 ; i > 63 - n; i--) {
v |= (1llu << i);
}
return v;
}
现在只是出于好奇,C中是否有任何方法可以在不使用循环(或查找表)的情况下完成相同的操作?
编辑:n = 0和n = 64是要处理的案例,就像循环变体一样。
答案 0 :(得分:6)
如果您对n = 0
案例无效,可以将其简化为
uint64_t set_n_high(int n)
{
return ~UINT64_C(0) << (64 - n);
}
除此之外,如果您对“奇怪的移位计数”(未定义的行为,但在我的机器上工作)没问题,您可以进一步简化
uint64_t set_n_high(int n)
{
return ~UINT64_C(0) << -n;
}
如果您对n = 64
案例无效,可以将其简化为
uint64_t set_n_high(int n)
{
return ~(~UINT64_C(0) >> n);
}
如果使用这意味着您必须验证n
,则速度不会更快。否则,它可能是。
如果你不对任何一种情况都不行,那就太麻烦了。这是一个建议(可能有更好的方法)
uint64_t set_n_high(int n)
{
return ~(~UINT64_C(0) >> (n & 63)) | -(uint64_t)(n >> 6);
}
请注意,否定无符号数是完全明确的。
答案 1 :(得分:5)
uint64_t set_n_high(int n) {
return ((1llu << n) - 1) << (64-n);
}
答案 2 :(得分:2)
好好接受@ harold的回答并稍微改变一下:
uint64_t set_n_high(int n)
{
int carry = n>>6;
return ~((~0uLL >> (n-carry)) >> carry);
}
答案 3 :(得分:2)
使用条件来处理n == 0
然后它变得微不足道。
uint64_t set_n_high(int n) {
/* optional error checking:
if (n < 0 || n > 64) do something */
if (n == 0) return 0;
return -(uint64_t)1 << 64 - n;
}
没有什么比这更复杂的事情了。完全指定从int
到uint64_t
的强制转换,以及否定和转移(因为如果n
在[0,则保证移位量位于[0,63]中64])。
答案 4 :(得分:1)
嗯,我呈现的是一个奇怪的 :)
/* works for 0<=n<=64 */
uint64_t set_n_high(int n)
{
return ~0llu << ((64 - n) / 4) << ((64 - n) * 3 / 4);
}
答案 5 :(得分:0)
对于它的价值,到目前为止的帖子(处理0-64的n),这个在x86_64和覆盆子pi上产生最少的组装(并且进行1分支操作)(使用gcc 4.8。 2)。它看起来也很可读。
uint64_t set_n_high2(int n)
{
uint64_t v = 0;
if (n != 0) {
v = ~UINT64_C(0) << (64 - n);
}
return v;
}