Python 中的按位减法

发布于 2024-07-11 11:07:02 字数 1044 浏览 8 评论 0原文

这是 我昨天的问题

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

This is a follow-up to my question yesterday:

CMS kindly provided this example of using bitwise operators to add two numbers in 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;
}

It works great and I then ported it to Python as follows:

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)

They both work for addition and the C program works for subtraction as well. However, the Python program enters an infinite loop for subtraction. I am trying to get to the bottom of this and have posted the program here for further experimentation: http://codepad.org/pb8IuLnY

Can anyone advise why there would be a difference between the way C handles this and the way CPython handles this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

水晶透心 2024-07-18 11:07:02

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

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

>>> 1 << 100
1267650600228229401496703205376L

你可以尝试这样的事情:

x = (a << 1) & 0xffffffff

要将结果限制为32位,问题是Python中的左移运算符不会移动a的符号位有符号数(这是使该特定解决方案发挥作用所需的一部分)。 可能有一种方法可以改变轮班操作员的行为,但我不知道如何做。

As I pointed out in my response to CMS' answer yesterday, left-shifting a negative number is undefined behavior in C so this isn't even guaranteed to work in C (the problem is how to handle the signed bit, do you shift it like a value bit or is it not affected by a shift? The standards committee couldn't agree on a behavior so it was left undefined).

When this happens to work in C it relies on fixed bit-width integers so that the leftmost bit gets pushed off the end when you do a shift (it also requires the sign bit to be treated as a value bit for shifting purposes). All integer types in C are fixed-bit but Python numbers can be arbitrarily large. Left-shifting a number in Python just causes it to keep getting larger:

>>> 1 << 100
1267650600228229401496703205376L

You could try something like this:

x = (a << 1) & 0xffffffff

To limit the result to 32-bits, the problem is that the left shift operator in Python doesn't shift the sign bit of a signed number (which is part of what is required to make this particular solution work). There might be a way to change the behavior of the shift operator but I don't know how.

说谎友 2024-07-18 11:07:02

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

Shifting negative numbers doesn't have consistent interpretation between python and C.

九厘米的零° 2024-07-18 11:07:02

如果ij是两个整数:

加法:

printf("%d",(i^j)|((i&j)<<1));

if i, j are two integers:

addition:

printf("%d",(i^j)|((i&j)<<1));
飘落散花 2024-07-18 11:07:02

我注意到您假设 python 处理数字的方式与 C 相同。
这并不完全正确。 这意味着 C 的 int 数字具有 16 位的固定长度。 有关 C 数据类型的详细信息,您可以参考 en.wikipedia.org 上的 C_data_types
另一方面,据说 Python 的 int 数字实际上具有无限长度。
添加正整数可能会以同样的方式工作。 但负整数的减法或加法不应该是简单的映射转换。
理解这一点的一个简单方法是一个关于负数的小例子:
想象一下 3 位的固定长度整数表示:
#无符号#

  • 000 : 0
  • 001 : 1
  • 010 : 2
  • 011 : 3
  • 100 > : 4
  • 101 : 5
  • 110 : 6
  • 111 : 7

#Signed:#

  • 000 : 0
  • 001 : 1
  • 010 : 2
  • 011 : 3
  • 100 : -4
  • 101 : -3
  • < code>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 中却行不通。

I've noticed that you're assuming that python works with numbers the same way as C does.
Thats not entirely true. Meaning C's int numbers have a fixed length of 16 bits. For detailed info on C datatypes you can refer to C_data_types on en.wikipedia.org
Python, on the other hand, is said to have a virtually infinite length for int numbers.
Adding positive integers may work the same way. But subtracting or adding negative integers shouldn't be a simple mapping translation.
An easy way to understand this is a little example on negative numbers:
Imagine a fixed length integer representation of 3 bits:
#Unsigned#

  • 000 : 0
  • 001 : 1
  • 010 : 2
  • 011 : 3
  • 100 : 4
  • 101 : 5
  • 110 : 6
  • 111 : 7

#Signed:#

  • 000 : 0
  • 001 : 1
  • 010 : 2
  • 011 : 3
  • 100 : -4
  • 101 : -3
  • 110 : -2
  • 111 : -1

This works cool because you can see that 1-3=1+(-3), -3 is 101 that's 5 if unsigned. So 1+5=6, 6 : 110 : -2. This means that 1-3=-2.
it also becomes buggy when overflowing:

  • -4 + -1 = 3 not -5 because it's out of range!
  • 3 + 1 = -4 not 4 because it's out of range!

As you may see this works for fixed length but it doesn't work this way in Python.

月下客 2024-07-18 11:07:02

对于任何仍然感兴趣的人,要解决 python 中的问题,只需添加一个新的 case 并切换函数内 x 和 y 的顺序,并返回负值,虽然这在函数中添加了“-”,但这提供了一种方法使用按位运算符。 对于仍然希望在以下问题中使用运算符“-”进行争论的人,我可以认为对于 2 - 6 的情况,正确的答案是 -4,其中答案中存在“-”,因此可以添加当x小于y时。 希望这可以帮助。

#使用位运算符将两个整数相减
#参考:https://www.geeksforgeeks.org /不使用算术运算符减去两个数字/

def subtractBits(x, y):
xRAW = x
yRAW = y
if x < y:
    x = y
    y = xRAW

# Iterate till there
# is no carry
while (y != 0):
 
    # borrow contains common
    # set bits of y and unset
    # bits of x
    borrow = (~x) & y
     
    # Subtraction of bits of x
    # and y where at least one
    # of the bits is not set
    x = x ^ y

    # Borrow is shifted by one
    # so that subtracting it from
    # x gives the required sum
    y = borrow << 1

if xRAW < yRAW:
    return -x
else:
    return x

print(subtractBits(100, 50))
print(subtractBits(1, 3))
print(subtractBits(40, 0))
print(subtractBits(0, 40))
print(subtractBits(5, 5))

For anyone are still interested, to resolve issue in python, just add a new case and switch the order of x and y inside the function, and return the negative value, though this put "-" in the function, but this presented a way using bit-wise operator. For anyone still wish to argue using operator "-" in the following question, I could argue that for the case of 2 - 6, the right answer is -4 where "-" exists in the answer, so it might be okay to add it when x is smaller than y. Hope this helps.

#A substract to substract two integers using bits operators
#refer to: https://www.geeksforgeeks.org/subtract-two-numbers-without-using-arithmetic-operators/

def subtractBits(x, y):
xRAW = x
yRAW = y
if x < y:
    x = y
    y = xRAW

# Iterate till there
# is no carry
while (y != 0):
 
    # borrow contains common
    # set bits of y and unset
    # bits of x
    borrow = (~x) & y
     
    # Subtraction of bits of x
    # and y where at least one
    # of the bits is not set
    x = x ^ y

    # Borrow is shifted by one
    # so that subtracting it from
    # x gives the required sum
    y = borrow << 1

if xRAW < yRAW:
    return -x
else:
    return x

print(subtractBits(100, 50))
print(subtractBits(1, 3))
print(subtractBits(40, 0))
print(subtractBits(0, 40))
print(subtractBits(5, 5))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文