如何使用位运算进行减法——教程

424 阅读4分钟

Subtraction using bitwise operations

读者朋友们好,我们来看看如何在不使用算术运算的情况下减去两个数字。我们将只使用位操作来进行减法。

内容表。

  1. 什么是顺位运算?
  2. 使用位操作进行减法
  3. 减法逻辑
  4. 逻辑的实现
  5. 复杂度分析

我们现在将深入研究位数减法。

什么是逐位运算?

与十进制数字系统中的算术运算符(如+,-,*,/ )类似,我们也有位运算符(如AND (&),OR (|),XOR (^) )来处理以比特形式存储的数据。

位操作符用于对存储在计算机内存中的数据进行位操作。

一些著名的位运算符是。

  1. &
  2. |
  3. XOR^
  4. 左移<<
  5. 右移>>
  6. 位数不是~

使用位操作的减法。

为了理解这一点,我们必须进入计算机内存中数据表示的二进制层面。
我将用十进制和二进制来解释,以使其尽可能清晰。

假设我们有两个数字xy ,它们的数值分别为。

int x = 5, y = 3;

我们必须在不使用任何算术运算符(如- (减))的情况下找出这两个数字的差异。

我们要利用的运算符来完成这个任务。

  1. XOR
  2. 比特不运算
  3. 左移

XOR

XOR是一个二进制运算符,如果比特是不同的比特,将返回1 ,相同的比特将返回0

5和3的XOR。

 5   3  | XOR
--- ---   ---
 1   1  |  0  --> Same bits results in 0
 0   1  |  1  --> Different bits results in 1
 1   0  |  1
 0   0  |  0

位数不运算 (~)

Bitwise NOT是一个单数运算符,非常容易理解,它只是简单地将位flips ,它将0 改为1 ,将1 改为0

~5将是。

 5 | ~5
---  ---
 1 |  0  --> Flips the bit
 0 |  1  
 1 |  0
 0 |  1

减法逻辑

对于二进制数字的减法,规则与十进制相似。当一个较大的数字要从一个较小的数字中减去时,我们从左边的下一列取一个borrow

让我们把二进制的数字形象化。

X     Y    Diff   Borrow
1     1     0       0
0     1     1       1
1     0     1       0
0     0     0       0

如果我们看一下位数差,我们可以很容易地推断出上面的位数减法的结果相当于我们对这些数字(x=5,y=3)进行xor ,这也会给我们留下差值。
x^y。

 x   y  | XOR
--- ---   ---
 1   1  |  0
 0   1  |  1 (with a borrow)
 1   0  |  1
 0   0  |  0

bitwise-not 现在,剩下的就是borrow ,如果我们对x ,然后用AND ,再用y ,就会剩下borrow

int x=5, y=3;

 ~x   y  |   AND
--- ---   --------
 0   1   |     0
 1   1   |     1
 0   0   |     0
 1   0   |     0

总结一下上述操作,减法将等于。

use (x^y) to get the difference
use ((~x)&y) to get carry bit

逻辑的实现

说到实现,我们可以用两种方式实现。

  • 迭代式
  • 递归

我们就来看看这两种方式。

1.迭代算法

for two given integers x, y:
    1. get the borrow/carry bit as it contains unset bits of x and 
       common bits of y
            int borrow = (~x)&y;
            
    2. get the difference using XOR and assign it to x:
           x = x^y
    
    3.Asssign the borrow to y by left shifting it by 1 so when we XOR it
      with x it gives the required sum.
          y = borrow << 1;
    
    4. Repeat the above steps until y becomes 0, in that case our carry will become 0.
    5. In the end, you will end up having x set to the difference between x and y.
       In that case, simply return x
          return x;

C++代码示例

#include <iostream>
using namespace std;
 
int subtractUsingBitwise(int x, int y)
{
    
    while (y != 0)  // Iterate until carry becomes 0.
    {
        // step 1: get the borrow bit
        int borrow = (~x) & y;
        
        // step 2: get the difference using XOR
        x = x ^ y;
        
        // step 3: left shift borrow by 1
        y = borrow << 1;
    }
    return x;
}
 
int main()
{
    int x = 5, y = 3;
    int answer = subtractUsingBitwise(x, y);
    cout << "x - y is : "<<answer<<endl;
    return 0;
}

2.递归算法

for two given integers x, y:
    1. Check if y is equal to 0, if so then return x (The base condition of recusrrsion):
           if (y==0) then
           return x;
            
    2. Else, assign x to the difference and y to the carry bit(left shifted by 1) 
      in each recursive call:
           x = x^y;
           y = ((~x) & y) << 1;
           call function recursively by passing x and y

C++代码示例

#include <iostream>
using namespace std;
 
int subtractUsingBitwise(int x, int y)
{
    if (y == 0) // step 1: base condition
       return x;
    
    // step 2: perform bitwise manipulation and assign x and y
    x = x^y;
    y = ((~x) & y) << 1;
    
    // step 3: call function recursively
    return subtractUsingBitwise(x, y);
}
 
int main()
{
    int x = 5,y = 3;
    cout << "x - y is "<< subtract(x, y);
    return 0;
}

复杂度分析

位减法的时间复杂度将是O(n) ,其中n 是一个数字的位数。
空间复杂度将保持不变,O(1) ,因为我们在每一步中没有使用任何额外的空间。

位操作被用于计算机科学的许多许多领域,以提高程序的效率。对位操作有深刻的理解,将有助于你开发更有效的解决方案。

这就是OpenGenus关于使用位操作符来处理数据以获得减法的文章的结尾。

希望它对你有帮助!