理解Python中的二进制加法使用位操作

huangapple go评论78阅读模式
英文:

Understanding binary addition in python using bit manipulation

问题

I am looking at solutions for this question:

Given two integers a and b, return the sum of the two integers without using the operators + and -. (Input Limits: -1000 <= a, b <= 1000)

In all these solutions, I am struggling to understand why the solutions do ~(a ^ mask) when a exceeds 32-bit number max 0x7fffffff when evaluating a + b [see code below].

def getSum(self, a: int, b: int) -> int:
    
    # 32bit mask
    mask = 0xFFFFFFFF # 8Fs = all 1s for 32 bits

    while True: 
        # Handle addition and carry 
        a, b = (a ^ b) & mask, ((a & b) << 1) & mask
        if b == 0:
            break

    max_int = 0x7FFFFFFF

    print("A:", a)
    print("Bin A:", bin(a))
    print("Bin M:", bin(mask))
    print("  A^M:", bin(a ^ mask))
    print("~ A^M:", bin(~(a ^ mask))
    print("  ~ A:", bin(~a))

    return a if a < max_int else ~(a ^ mask)

I don't get why we need to mask a again when returning the answer.

When exiting the loop it was already masked: a = (a ^ b) & mask. So why can't we just do ~a if the 32nd bit is set to 1 for a?

I looked at https://stackoverflow.com/questions/46573219/the-meaning-of-bit-wise-not-in-python, to understand ~ operation, but did not get it.

Output for a = -12, b = -8. Correctly returns -20:

A: 4294967276
Bin A: 0b11111111111111111111111111101100
Bin M: 0b11111111111111111111111111111111
  A^M: 0b10011
~ A^M: -0b10100
  ~ A: -0b11111111111111111111111111101101
英文:

I am looking at solutions for this question:
> Given two integers a and b, return the sum of the two integers without using the operators + and -. (Input Limits: -1000 <= a, b <= 1000)

In all these solutions, I am struggling to understand why the solutions do ~(a ^ mask) when a exceeds 32-bit number max 0x7fffffff when evaluating a + b [see code below].

def getSum(self, a: int, b: int) -&gt; int:
    
    # 32bit mask
    mask = 0xFFFFFFFF # 8Fs = all 1s for 32 bits

    while True: 
        # Handle addition and carry 
        a, b = (a ^ b) &amp; mask, ((a &amp; b) &lt;&lt; 1) &amp; mask
        if b == 0:
            break

    max_int = 0x7FFFFFFF

    print(&quot;A:&quot;, a)
    print(&quot;Bin A:&quot;, bin(a))
    print(&quot;Bin M:&quot;, bin(mask))
    print(&quot;  A^M:&quot;, bin(a ^ mask))
    print(&quot;~ A^M:&quot;, bin(~(a ^ mask)))
    print(&quot;  ~ A:&quot;, bin(~a))

    return a if a &lt; max_int else ~(a ^ mask)

I don't get why we need to mask a again when returning answer?

When exiting the loop it was already masked: a = (a ^ b) &amp; mask. So why can't we just do ~a if the 32nd bit is set to 1 for a?

I looked at https://stackoverflow.com/questions/46573219/the-meaning-of-bit-wise-not-in-python, to understand ~ operation, but did not get it.

Output for a = -12, b = -8. Correctly returns -20:

A: 4294967276
Bin A: 0b11111111111111111111111111101100
Bin M: 0b11111111111111111111111111111111
  A^M: 0b10011
~ A^M: -0b10100
  ~ A: -0b11111111111111111111111111101101

答案1

得分: 2

你忘了指定原问题的限制条件,即ab在[-1000, 1000]之间。那段代码是C或Java实现的移植版本,假设ab是4字节有符号整数。我不确定你是否正确理解了(a ^ b)(a &amp; b) &lt;&lt; 1的代码。前者忽略了每一位的进位,将ab的第i位相加。后者获得了所有被忽略的进位位。

至于最后的操作~(a ^ mask)是用于处理负整数。a ^ mask反转了a的低32位并保留其他高位。所以结果的按位非运算~(a ^ mask)保留了a的低32位并反转了其他高位。因为a的高位(除了低32位)全为零,~(a ^ mask)实际上是将所有高位设置为1。这等同于a | ~mask,更易读。

看下面的例子。

print(~(0xffffffff ^ 0xffffffff)) # 这将输出-1。
print(~(0xfffffffe ^ 0xffffffff)) # 这将输出-2。
print(~0xffffffff) # 这将输出-4294967296(-0x100000000)。
英文:

You forgot to specify constraints of the original problem, that the a and b are in [-1000, 1000]. That code is a port of a C or Java implementation, which assumes a and b are 4 byte signed integers. And I'm not sure you understand the (a ^ b) and (a &amp; b) &lt;&lt; 1 code correctly. The former adds i-th bit of the a and b ignoring a carry bit for every bit. The latter gets all that ignored carry bits.

To the main point, the last operation ~(a ^ mask) is for dealing with a negative integer. The a ^ mask inverts the lower 32 bits of the a and preserves the other upper bits. So, the bitwise NOT of the result, ~(a ^ mask) preserves the lower 32 bits of the a and inverts the other upper bits. Because the upper bits(other than the lower 32 bits) of the a are all zero, the ~(a ^ mask) is just setting all the upper bits to one. It's equivalent to a | ~mask, which is much more readable.

See the following example.

print(~(0xffffffff ^ 0xffffffff)) # This will output -1.
print(~(0xfffffffe ^ 0xffffffff)) # This will output -2.
print(~0xffffffff) # This will output -4294967296(-0x100000000).

答案2

得分: 0

这是一个有用的链接 - https://stackoverflow.com/questions/50659567/differentiating-a-2s-complement-negative-number-and-the-corresponding-positive

由于范围限制,我们永远不会有正数溢出(数字仅在[-1000, 1000]之间)。因此,我们知道当第32位被设置时,这是因为它是一个负数。

请注意,如果我们的范围允许正数相加也溢出,那么就没有办法区分正数设置第32位和负数设置第32位。

因此,我们执行~(a ^ mask)来保留a的位直到第32位,并在其前添加无限数量的1,以便Python知道这是一个负数。

如果您看Bin A,它已经是-20的二进制补码表示,但现在Python将其视为正数。因此,我们需要告诉Python使用~(a ^ mask)将其视为负数。

英文:

Here's a helpful link - https://stackoverflow.com/questions/50659567/differentiating-a-2s-complement-negative-number-and-the-corresponding-positive.

Because of the bounds, we will never have a positive number overflow. (numbers are only between [-1000, 1000]). So we know that when the 32nd bit was set it was because it was a negative number.

Note that if our range allowed positive number addition to overflow too, then there would be no way to distinguish between positive number setting 32nd bit and negative number setting it.

So we do ~(a ^ mask) to retain bits of a till the first 32 bits and add infinite leading 1s to it so Python knows this is a negative number.

If you look at Bin A, it's already the 2s complement representation of -20. But right now Python treats it as a positive number. So we need to tell Python to treat it as a negative number using ~(a ^ mask).

huangapple
  • 本文由 发表于 2023年2月19日 03:21:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75495814.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定