这是my question yesterday的后续行动:
CMS提供了这个使用按位运算符在C中添加两个数字的示例:
#include<stdio.h>
int add(int x, int y) {
int a, b;
do {
a = x & y;
b = x ^ y;
x = a << 1;
y = b;
} while (a);
return b;
}
int main( void ){
printf( "6 + 3 = %d", add(6,3));
printf( "6 - 3 = %d", add(6,-3));
return 0;
}
它工作得很好,然后我按如下方式将它移植到Python:
def add(x, y):
while True:
a = x & y
b = x ^ y
x = a << 1
y = b
if a == 0:
break
return b
print "6 + 3 = %d" % add(6,3)
print "6 - 3 = %d" % add(6,-3)
它们都适用于加法,C程序也适用于减法。但是,Python程序进入减法的无限循环。我正试图深入了解并在此处发布该程序以进行进一步的实验:http://codepad.org/pb8IuLnY
有人可以建议为什么C处理这个问题的方式与CPython处理这个问题的方式有区别吗?
答案 0 :(得分:9)
正如我昨天在回答CMS回答中指出的那样,左移一个负数是C中的未定义行为,所以这甚至不能保证在C中工作(问题是如何处理有符号的位,做你把它转移到一个有价值的位置,还是不受转变的影响?标准委员会无法就行为达成一致,因此未定义。
当这种情况发生在C中时,它依赖于固定的位宽整数,这样当你进行移位时,最左边的位就会被推到末尾(它还需要将符号位作为一个值位来处理,以便进行移位) )。 C中的所有整数类型都是固定位,但Python数字可以任意大。在Python中左移一个数字只会导致它变大:
>>> 1 << 100
1267650600228229401496703205376L
您可以尝试这样的事情:
x = (a << 1) & 0xffffffff
要将结果限制为32位,问题在于Python中的左移位运算符不会移位带符号数的符号位(这是使此特定解决方案工作所需的部分)。可能有一种方法可以改变移位运算符的行为,但我不知道如何。
答案 1 :(得分:2)
移位负数在python和C之间没有一致的解释。
答案 2 :(得分:1)
如果i
,j
是两个整数:
此外:
printf("%d",(i^j)|((i&j)<<1));
答案 3 :(得分:0)
我注意到你假设python与C一样使用数字。
那不完全正确。含义C的int numbres具有16位的固定长度。有关C数据类型的详细信息,请参阅C_data_types on en.wikipedia.org
另一方面,据说Pyhton对于int数字几乎没有任何长度
添加正整数可能会以相同的方式工作。但减去或添加负整数不应该是简单的映射转换。
理解这一点的简单方法是关于负数的一个小例子:
想象一下3位的固定长度整数表示:
000
:0 001
:1 010
:2 011
:3 100
:4 101
:5 110
:6 111
:7 000
:0 001
:1 010
:2 011
:3 100
:-4 101
:-3 110
: - 2 111
: - 1 这很酷,因为您可以看到1-3=1+(-3)
,-3是101
,如果未签名则为5。所以1+5=6
,6:110
: - 2。这意味着1-3=-2
。
溢出时它也会变成越野车:
- -4 + -1 = 3
不是-5,因为它超出了范围!
- 3 + 1 = -4
不是4,因为它超出了范围!
正如您可能看到的,它适用于固定长度,但它在Python中不起作用。