使用按位运算连接位。这甚至可能吗?

时间:2014-11-19 11:20:19

标签: language-agnostic programming-languages bit-manipulation

我要问的是,是否可以加入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中起作用。

这有可能以任何方式吗?

如果我不清楚,请在评论中提出疑问。

3 个答案:

答案 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(),然后再重新申请登录你想要的方式。