我需要提出一个函数,它接受一个char和一个设置位的索引,并隔离一个包含该位的1的字符串。
即
char isolate(unsigned char arg, int i);
例如:
隔离(221,2)将返回28(11011101>>>> 00011100)
isolate(221,6)将返回192(11011101>>>> 1100000)
查找表似乎是一个笨拙的解决方案,因为它需要~256 * 8 = 2048个条目。
我正在考虑检查索引左侧和右侧的每个位:
char isolate(char arg, int i)
{
char result=0;
char mask = 1<<i;
for(char mask = 1<<i; arg & mask != 0; mask>>=1)
result |= mask;
for(char mask = 1<<i; arg & mask != 0; mask<<=1)
result |= mask;
return result;
}
但它似乎有点难看。我怎么能比这更好呢?
答案 0 :(得分:3)
这是一个有趣的操作。你写的代码表达得相当好,所以你会想一想它是如何丑陋的吗?
我可以看到的细节:鉴于i
表示arg
中的位数,i
中更宽泛的类型绝对没有意义。在一个条件下编写!= 0
从来都没有意义。您可能不希望在使用它的任何地方重新声明掩码,也不想连续两次初始化它。
至于实际的扩散位掩码,我想不出现在更具表现力,更清晰或更有效的方式。
答案 1 :(得分:0)
警告:这些都没有经过测试甚至是相关的*,但它可能很有趣。
隔离最右边的1s非常简单,例如:x ^ (x & ((x|(x-1))+1))
(下面的说明),让我们一起使用。
第一个x|(x-1)
将最右边的1涂抹到右边,将所有这些位加1圈,包括最右边的1个,并且x
删除最右边的1个,最后,xoring x
只留下最右边的1s。
然后我们只需要确保我们正在寻找的范围是最右边的。这不太适合简单的bitmath,但如果有Count Leading Zeros(clz
),那就不太难了:
int shift = 32 - clz(~x & ((1 << i) - 1)); //replace 32 with word size
x = (x >> shift) << shift;
((1 << i) - 1)
制作了我们正在寻找的游戏右端所在的部分的掩码(它也可能只是错过了结尾,但没关系) ,然后clz
查找i
中x
右侧的第一个零,然后移位移除我们不想查看的位。
应用第一个公式,用于隔离最右边的1s运行结果,以获得i
所在的运行结果。i
最好在某些运行中运行,或者事情侧身(更准确地说,它将返回从索引高于i
开始的第一轮1s)
*:对于这个问题,这一切都不重要。一个2KB的表并不是一个笨拙的解决方案,除非你只有很少的可用内存,即使是这样,输入也很短,所以循环并不是那么糟糕。