英文:
Understanding binary addition in python using bit manipulation
问题
I am looking at solutions for this question:
Given two integers
a
andb
, 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) -> 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 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
答案1
得分: 2
你忘了指定原问题的限制条件,即a
和b
在[-1000, 1000]之间。那段代码是C或Java实现的移植版本,假设a
和b
是4字节有符号整数。我不确定你是否正确理解了(a ^ b)
和(a & b) << 1
的代码。前者忽略了每一位的进位,将a
和b
的第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 & b) << 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
由于范围限制,我们永远不会有正数溢出(数字仅在[-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)
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论