Python中的逐位减法

时间:2008-12-14 16:41:28

标签: python low-level

这是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处理这个问题的方式有区别吗?

4 个答案:

答案 0 :(得分:9)

正如我昨天在回答CMS回答中指出的那样,左移一个负数是C中的未定义行为,所以这甚至不能保证在C中工作(问题是如何处理有符号的位,做你把它转移到一个有价值的位置,还是不受转变的影响?标准委员会无法就行为达成一致,因此未定义。

当这种情况发生在C中时,它依赖于固定的位宽整数,这样当你进行移位时,最左边的位就会被推到末尾(它还需要将符号位作为一个值位来处理,以便进行移位) )。 C中的所有整数类型都是固定位,但Python数字可以任意大。在Python中左移一个数字只会导致它变大:

>>> 1 << 100
1267650600228229401496703205376L

您可以尝试这样的事情:

x = (a << 1) & 0xffffffff

要将结果限制为32位,问题在于Python中的左移位运算符不会移位带符号数的符号位(这是使此特定解决方案工作所需的部分)。可能有一种方法可以改变移位运算符的行为,但我不知道如何。

答案 1 :(得分:2)

移位负数在python和C之间没有一致的解释。

答案 2 :(得分:1)

如果ij是两个整数:

此外:

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中不起作用。