没有算术运算符的A + B, Python与c++
A + B without arithmetic operators, Python vs C++
我试图解决一个老问题:
编写一个函数,将两个[整数]数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;
}
};
我不知道具体应该问什么,基本上问题是:
- 为什么c++给出正确的输出
0
而Python没有? - 如果我使用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=4
和b=-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)
如前所述,按位是更好的。
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- Pybind11:将元组列表从Python传递到C++
- 如何在c++中使用引用实现类似python的行为
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 递归列出所有目录中的C++与Python与Ruby的性能
- IPC使用多个管道和分支进程来运行Python程序
- 从python中调用C++函数并获取返回值
- Python 3.7 和 excess_args 的 SWIG 问题
- Python中的for循环与C++有何不同
- 使用Pybind11向Python公开Eigen::张量
- Python str to C++ to Python str
- 如何使用Python从C++中读取谷物序列化数据
- 如何在C++中使用pybind11加载一个pickle python列表
- 如何在c++中使用system()来运行包含空格的python脚本
- python集合的C++等价物是什么.计数器
- 如果C++对象的类在另一个boost模块中声明,如何使用boost将指向该对象的指针返回到python
- 从python调用openMP共享库时,未定义opnMP函数
- 使用JsonCpp将数据返回到带有pybind11的python会在python调用中产生Symbol not foun
- 如何将真正的字符串从python c-api转换为python脚本
- Python ctype 'c_char_p' Memory Leak