没有算术运算符的A + B, Python与c++

A + B without arithmetic operators, Python vs C++

本文关键字:Python c++ 运算符      更新时间:2023-10-16

我试图解决一个老问题:

编写一个函数,将两个[整数]数a和b相加,不能使用+或任何算术运算符。

最好的解决方案是这样的,引用自"LintCode-A+B Problem":

对于任意底数的a + b,我们可以把加号分成两部分:1。A + b不进位;2. 由a +b生成的进位。a+b就等于第一部分加上第二部分。如果part1+part2产生更多进位,我们可以重复这个过程,直到没有进位。

我可以理解这个算法,一切看起来都很好,所以我在lintcode上测试了它,代码粘贴在下面。

class Solution:
    """
    @param a: The first integer
    @param b: The second integer
    @return:  The sum of a and b
    """
    def aplusb(self, a, b):
        while b != 0:
            carry = a & b
            a = a ^ b
            b = carry << 1
        return a
但令人惊讶的是,它在测试用例[100, -100]中给了我Time Limit Exceeded错误。因此,我在本地运行它并为每个循环打印a, b:
(-8, 8)
(-16, 16)
(-32, 32)
(-64, 64)
(-128, 128)
(-256, 256)
(-512, 512)
(-1024, 1024)
(-2048, 2048)
(-4096, 4096)
(-8192, 8192)
(-16384, 16384)
(-32768, 32768)
(-65536, 65536)
(-131072, 131072)
...

计算是正确的,所以我认为这个算法不适合这样的输入,但当我在c++中编写相同的算法时,它只是工作:

class Solution {
public:
    int aplusb(int a, int b) {
        while (b!=0){
            int carry = a & b;
            a = a^b; 
            b = carry << 1;
        }
        return a;
    }
};

我不知道具体应该问什么,基本上问题是:

  1. 为什么c++给出正确的输出0而Python没有?
  2. 如果我使用Python,我如何修改这个算法使其工作?

-4的二进制,2的补码表示为

...11100

是的,我的意思是左边有无穷多个1;这是一个二进制重复数。从技术上讲,4也是一个重复数字:

...00100

它只是在左边重复0

你的加法问题是

   ...11100
+  ...00100
--------------------
   ...00000

运算符^, <<&在计算无穷多个二进制数字时没有问题,但问题是有无穷多个进位,并且每次计算一个数字。这永远不会结束。

因此,你必须认识到这个算法何时会陷入这种情况,并做一些其他的事情来解释它。


在C/c++中你不会遇到这个问题,因为,例如,如果int是32位的,那么除了最右边的31位之外的所有数字都被折叠成一个位,所以它会一次完成剩余的进位。

然而,从技术上讲,左移int的意义是将值作为整数,而不是作为位模式,所以如果carry的两个最高位不同,则调用未定义行为(,因为carry << 1会产生溢出)。

问题是负数,或者它们是如何表示的。在Python中,整数具有任意精度,而c++ int为32位或64位。因此,在Python中,您必须单独处理负数,例如减法,或者手动限制位数。

在@Hurkyl的精彩解释之后,我使用python实现了无限2的互补表示这一事实,逐步介绍了a=4b=-4的算法:

Step 0:
a = ...(0)...000100
b = ...(1)...111100
carry = a & b = ...(0)...000100
a = a ^ b = ...(1)...111000
b = carry << 1 = ...(0)...001000
Step 1:
a = ...(1)...111000
b = ...(0)...001000
carry = a & b = ...(0)...001000
a = a ^ b = ...(1)...110000
b = carry << 1 = ...(0)...010000
Step 2:
a = ...(1)...110000
b = ...(0)...010000
carry = a & b = ...(0)...010000
a = a ^ b = ...(1)...100000
b = carry << 1 = ...(0)...100000

很明显,需要一个有效的截止来模拟32位有符号的二进制补充整数。一旦进位冒泡超过最高位,算法就需要停止。下面的代码似乎可以工作:

MAX_BIT = 2**32
MAX_BIT_COMPLIMENT = -2**32
def aplusb(a, b):
    while b != 0:
        if b == MAX_BIT:
            return a ^ MAX_BIT_COMPLIMENT
        carry = a & b
        a = a ^ b
        b = carry << 1
    return a

结果:

>>> aplusb(100,-100)
0
>>> aplusb(100,-99)
1
>>> aplusb(97,-99)
-2
>>> aplusb(1000,-500)
500
>>> aplusb(-1000,8000)
7000

如果1位的数学运算(^)是被禁止的,那就使用一元!

from itertools import chain
def unary(x):
    "Unary representation of x"
    return ''.join(['x' for _ in range(0,x)])
def uplus(x, y):
    "Unary sum of x and y"
    return [c for c in chain(x,y)]
def plus(i, j):
    "Return sum calculated using unary math"
    return len(uplus(unary(i), unary(j)))

这是因为python通常不使用32位有符号整型。

看到:ctypes.c_int32

接受解决方案:

class Solution:
"""
@param a: The first integer
@param b: The second integer
@return:  The sum of a and b
"""
def aplusb(self, a, b):
    import ctypes
    a = ctypes.c_int32(a).value
    a = ctypes.c_int32(a).value
    while b != 0:
        carry = ctypes.c_int32(a & b).value
        a = ctypes.c_int32(a ^ b).value
        b = ctypes.c_int32(carry << 1).value
    return a

我的解决方案:

def foo(a, b):
"""iterate through a and b, count iteration via a list, check len"""
    x = []
    for i in range(a):
            x.append(a)
    for i in range(b):
            x.append(b)
    print len(x)

如前所述,按位是更好的。