什么是a ^ b和(a&b)<< 1?

时间:2019-03-16 03:22:42

标签: javascript bitwise-operators

我正在用leetcode执行此question

请求:

  

计算两个整数a和b的总和,但不允许使用+和-运算符。

我不明白它提供的解决方案

有人可以解释此getSum函数的工作原理吗?

这是JS中的答案:

var getSum=function(a,b) {
    const Sum = a^b; //I can't understand how those two line's code can
    const carry = (a & b) << 1; //get the sum
        if(!carry) {
            return Sum
        }
    return getSum(Sum,carry);
};
console.log(getSum(5,1));

4 个答案:

答案 0 :(得分:35)

它基本上是在复制half-adder

将A和B的两个位相加会产生2个输出:和和进位如下所示

╔═══════╤═════════════╗
║ Input │   Output    ║
╠═══╤═══╪═══════╤═════╣
║ A │ B │ carry │ sum ║
╟───┼───┼───────┼─────╢
║ 0 │ 0 │   0   │  0  ║
╟───┼───┼───────┼─────╢
║ 1 │ 0 │   0   │  1  ║
╟───┼───┼───────┼─────╢
║ 0 │ 1 │   0   │  1  ║
╟───┼───┼───────┼─────╢
║ 1 │ 1 │   1   │  0  ║
╚═══╧═══╧═══════╧═════╝

从表中我们获得输出的逻辑:进位= A和B sum = A xor B

XOR也称为无进位加法运算符,由represented表示,其中带有+符号

所以上面的代码片段是这样工作的

const Sum=a^b;              // sum = a xor b = a ⊕ b
const carry=(a&b)<<1;       // carry = 2*(a and b), since we carry to the next bit
if(!carry){
    return Sum;             // no carry, so sum + carry = sum
}
return getSum(Sum,carry);   // a + b = sum + carry

因此a^b同时将a和b中的每一位相加,而在Sum中保留a和b的非进位和。然后,我们必须将进位加到无进位总和上,以得到最终结果,因为我们只有一个半加法器,而不是一个全加法器,它执行a + b = a⊕b +进位

另请参见

答案 1 :(得分:26)

让我们以身作则。想象一下a = 3b = 5

以二进制表示法是a = 0011b = 0101

异或: a^b是XOR运算符。比较两个位时,如果相同则返回0,如果不同则返回101^10 => 11

因此,当我们执行a^b时,结果将是0110

AND + SHIFT

a&b执行逻辑AND操作。仅在a = b = 1时返回1。

在我们的例子中,结果为0001

<<将其移动(在右侧添加0),结果变为0010,将carry变量设置为true。 (只有0000为假)。

下一次迭代:

一切重复,但是现在a = 0110b = 0010(上次执行的Sumcarry

现在a^b = 0100(a&b)<<1 = 0100

再次重复。

现在a^b = 0000(a&b)<<1 = 1000

再次。

现在a^b = 1000(a&b)<<1 = 0000。现在carry最终是false。然后我们返回1000,它是十进制8

3+5=8以来一切正常

答案 2 :(得分:2)

 int result = p ^ q; // XOR Operator, + without carry 0+0=0, 0+1=1+0=1, 1+1=0
int carry = (p & q) << 1; // Left Shift, 1+1=2
if (carry != 0) {
    return getSum(result, carry);
}
return result;

从p = 5,q = 6开始。那么XOR就是

0101
0110
------
0011

因此,“异或”运算结果为(0011),实际上是十进制的3。然后,将p和q相加,得到

0101
0110
-------
0100

通过对5和6进行“与”运算,我们得到4(二进制数为100),现在,如果将该值左移1,我们将得到

 0100<<1=1000

因此,第一次递归后得到8(二进制数为1000)。由于结果(进位变量)不为零,请通过异或值和进位值再次递归。

getSum(3, 8);

因此,进行第一个XOR运算,

0011
1000
-------
1011

这次的异或运算产生11(1011二进制),所以我们现在执行AND,

0011
1000
-------
0000

我们得到与3和8的所有零值,因此这一次左移运算符也将产生零值,因为这里没有1,可能会通过左舍入零来给我们一个值。 由于进位变量现在为零,因此我们进行了递归操作,并且XORed值将为Sum,即11(二进制为1011)。

希望您可以执行该程序。您可以通过学习按位运算来了解更多信息,这是机器进行算术运算的方式。

答案 3 :(得分:0)

^是XOR,按位运算。在单个位上,规则是0 ^ 0 = 00 ^ 1 = 11 ^ 0 = 01 ^ 1 = 0,在处理多位值时,只需扩展对相应位的执行即可。该名称是“ exclusive or”的缩写,它来自于以下事实:A ^ B1,当且仅当A或B中的任何一个为1时,两者都不是。但是,谈论它的另一个名称⊕更有趣。 ⊕是+,但略有不同。您会注意到⊕的规则与加法规则相似:0 + 0 = 00 + 1 = 11 + 0 = 11 + 1 = 10。 {是+,1 ⊕ 1 = 0除外;也就是说,⊕是+,除非没有携带。这适用于多个位:011 + 001 = 100,因为您将1移出了四位,然后又将1移到了四位。然后,011 ⊕ 001 = 010,因为您根本不携带。

现在,当进行真正的加法时,什么时候携带?用二进制表示,答案很简单:给定位置有两个1时,将1带到下一个位置。这很容易理解为按位与&1 & 1 = 1,否则0。对于011 + 001,不带加法的加法会得到011 ⊕ 001 = 010,我们可以知道我们需要将1移出那个位置,因为011 & 001 = 001(a & b) << 1中的移位变成一个数字“我需要从哪里携带?”放入“我需要在何处添加进位?”:(011 & 001) << 1 = 010;我需要在两个位置加一个进位。

因此,在getSum中,我们想知道a + b。我们不用加a ^ b就可以算出加法,然后找到需要用(a & b) << 1加进位的地方。现在,我们只需要将这两个加在一起即可。好了,我们已经有了一个将数字加在一起的功能;它称为getSum。因此,我们基本上只写了function getSum(a, b) { return getSum(a ^ b, (a & b) << 1); },除了在没有东西要携带的情况下确保短路之外,这使我们免于无限递归。