我要问的是,是否可以加入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;
我想将此限制为仅限于按位运算符(>>
,<<
,|
,^
,{{1} }和~
)。
这应该至少在PHP和Javascript中起作用。
这有可能以任何方式吗?
如果我不清楚,请在评论中提出疑问。
答案 0 :(得分:1)
如果我理解你的问题,
这应该是php中的答案:
$temp = $your_first_value << strlen(dechex($the_length_of_the_second_value_in_hex))
$result = $temp | $your_second_value
print dechex($result)
更新:而不是+使用|操作
答案 1 :(得分:1)
这个问题完全取决于能否确定最左边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
,?:
,{{ 1}}等),控制流实际上是完全线性的(函数调用只是为了防止重复代码,所有内容都可以内联)。
这是另一种选择。而不是采用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;
}
答案 2 :(得分:0)
根据您的计算机的字节顺序,您可能必须颠倒下面的字节[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;
(感谢对this SO thread进行位计数算法)对于已签名的数字,我建议您在拨打此号码前使用abs()
,然后再重新申请登录你想要的方式。