提问人:Ismael Miguel 提问时间:11/19/2014 最后编辑:Ismael Miguel 更新时间:11/21/2014 访问量:381
使用按位运算连接位。这甚至可能吗?
Join bits using bitwise operations. Is this even possible?
问:
我要问的是是否可以将所有位连接成 2 个不同的数字。
伪代码示例:
bytes=array(0x04, 0x3F);
//place bitwise black magic here
print 0x043F;
另一个例子:
bytes=array(0xFF, 0xFFFF);
//place bitwise black magic here
print 0xFFFFFF;
再举一个例子:
bytes=array(0x34F3, 0x54FD);
//place bitwise black magic here
print 0x34F354FD;
我想将其限制为仅且仅按位运算符(、、、和)。>>
<<
|
^
~
&
这至少应该在 PHP 和 Javascript 中起作用。
这有可能吗?
如果我不清楚,请在评论中提出您的疑问。
答:
如果我正确理解了您的问题,
这应该是 php 中的答案:
$temp = $your_first_value << strlen(dechex($the_length_of_the_second_value_in_hex))
$result = $temp | $your_second_value
print dechex($result)
更新:使用 |算子
评论
$temp = $your_first_value << $the_length_of_the_second_value_in_hex
$temp = $your_first_value << 8
数字
)。$your_second_value
What I am asking is if it is possible to join all bits in 2 different
根据计算机的字节序,可能需要颠倒下面的字节 [0] 和字节1 的顺序:
uint8_t bytes[2] = { 0x04, 0x3f };
uint16_t result = (bytes[0] << 8) | bytes[1];
(这是用C语言写的,翻译成PHP等应该不难,语言和运算符足够相似)
更新:好了,既然你已经明确了你想要什么,基本方法仍然是一样的。相反,您可以做的是计算右侧数字中的位数,然后在左侧数字上执行位移,只需使用动态位数即可。只要您的位数不超过您的语言/平台支持的最大数值类型,这就可以工作,因此在此示例中为 64 位。
int rightMaxBits = 0;
uint64_t leftNum = 0x04, rightNum = 0x3f;
uint64_t rightNumCopy = rightNum;
while( rightNumCopy )
{
rightNumCopy >>= 1;
rightMaxBits++;
}
uint64_t resultNum = (leftNum << rightMaxBits) | rightNum;
(感谢此 SO 线程的位计数算法)对于有符号的号码,我建议您在拨打此号码之前使用该号码,然后以您想要的任何方式重新应用符号。abs()
评论
数字
)。不同之处在于它不仅限于字节。如果第二个数字介于 0 和 255 之间,则您的解决方案效果很好。What I am asking is if it is possible to join all bits in 2 different
bytes[1]
0x00
0xff
0x1ff
这个问题完全取决于能否确定整数中最左边的 1 的位置。一种方法是“正确涂抹位”,然后数 1:
向右涂抹:
int smearright(int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x;
}
简单,那里只有按位运算符。然而,计算位数涉及某种加法:
int popcnt(int x) {
x = add(x & 0x55555555, (x >> 1) & 0x55555555);
x = add(x & 0x33333333, (x >> 2) & 0x33333333);
x = add(x & 0x0f0f0f0f, (x >> 4) & 0x0f0f0f0f);
x = add(x & 0x00ff00ff, (x >> 8) & 0x00ff00ff);
x = add(x & 0xffff, (x >> 16) & 0xffff);
return x;
}
但没关系,可以实现为add
int add(int x, int y) {
int p = x ^ y;
int g = x & y;
g |= p & (g << 1);
p &= p << 1;
g |= p & (g << 2);
p &= p << 2;
g |= p & (g << 4);
p &= p << 4;
g |= p & (g << 8);
p &= p << 8;
g |= p & (g << 16);
return x ^ y ^ (g << 1);
}
把它放在一起:
join = (left << popcnt(smearright(right))) | right;
如果你有加法(没有函数),这显然要容易得多,也许令人惊讶的是,它甚至比乘法更简单:add
join = (left * (smearright(right) + 1)) | right;
根本没有了!popcnt
根据按位运算符实现乘法无济于事,这要糟糕得多,我不确定您甚至可以使用列出的运算符来做到这一点(除非正确的移位是算术移位,但这仍然是一件可怕的事情,涉及 32 个加法,每个加法都是函数本身)。
这个答案中没有“鬼鬼祟祟的伎俩”,比如使用隐式测试与零相等的条件(“隐藏”在 、 等中),控制流实际上是完全线性的(函数调用只是为了防止重复代码,一切都可以内联)。!= 0
if
?:
while
这是另一种选择。而不是采取 ,做一个奇怪的变量移位:popcnt
int shift_by_mask(int x, int mask) {
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
mask >>= 1;
x <<= mask & 1;
return x;
}
好吧,这不会让我高兴,但这是你如何使用它:
join = shift_by_mask(left, smearright(right)) | right;
评论
do{}while
下一个:证明类型声明语法的语法歧义
评论
~