在这篇文章中,我们解释了如何使用位运算符,如and,xor, 和left shift 运算符,而不是使用普通的加法运算符 (+),来实现任意两个正数的相加。
主题表。
- 位操作的基础知识
- 使用位操作符进行两个数的相加
- 使用递归进行位加
- 位加法的时间和空间复杂度
比特运算的基础知识
我们知道,计算机以二进制数字0s和1s的形式存储各种数据(视频、文件、照片等)。这些0s和1s被称为比特,可以对这些二进制数字进行的各种运算被称为顺位运算。
下面给出了各种位运算符
让我们举个例子,看看这些运算是如何工作的。
考虑两个十进制数字a 和b 。
a = 25 ,25的二进制等价物是 00011001
b = 14 ,14的二进制等价物是 00001110
1.位数和- 位数和只有在两个位都是1的情况下才会返回1。
2.2.顺时针或- 顺时针或在任何一个位是1的情况下返回1。
3.比特不运算 - 比特不运算返回位的补码。
4.Bitwise Xor- Bitwise xor只有在其中一个位为零时才会返回1。
5.位数左移
在上图中,我们可以看到三个0,在右边,也就是在最小有效位之后,导致向左移动。
6.位向右移
在上图中,我们可以看到三个0,在左边,即最有意义的位之后,导致向右移位。
现在我们已经了解了分位运算符的工作原理,让我们继续进行没有加法运算符的两数相加。
使用逐位运算符的两个数字相加
让我们先看看二进制层面的加法是如何发生的,并在尝试用位操作符做加法之前理解它。
二进制加法与通常的加法很相似。从上面的例子中,我们可以了解到
1 + 0 = 0 + 1 = 10 + 0 = 11 + 1 = 10,即2的二进制等价物。
另一个需要注意的要点是,当我们得到10 ,1 被带到进位,0 被保留在底部。
真值表会让我们更好地理解二进制加法是如何发生的。
从真值表中,我们可以推断出
- 进位表达式是
A & B - 和表达式为
A ^ B
利用以上两个表达式,任何两个数字的加法都可以按以下步骤完成。
步骤
- 得到两个正数
a和b作为输入 - 然后检查数字
b是否不等于0- 找到
carry的值 (a & b) - 找到
sum的值(a ^ b),并将其存入变量中。a - 然后将进位向左移动1位,将其存入变量中。
b
- 找到
- 再次回到步骤2
- 当b变成0时,最后返回总和
def Bitwise_add(a,b):
while b != 0:
carry = a&b # Carry value is calculated
a = a^b # Sum value is calculated and stored in a
b = carry<<1 # The carry value is shifted towards left by a bit
return a # returns the final sum
这段代码背后的整个想法是,进位与和值再次相加。所以我们要做的是,用表达式a & b ,分别找到进位的值,然后再用它来找和。我们一直这样做,直到进位值变成0。
这里需要注意的另一点是,我们将进位向左移了1位。这是因为进位值被添加到下一个位,而不是当前位。看一下这张图片,以获得更好的理解。
我们继续重复这个过程,直到结转值,即a & b ,变成0 。最后,我们得到所需的两个数字的总和。
使用递归进行位加
使用位运算符的加法也可以用递归的方式进行。同样的逻辑发生,但我们使用一个递归函数来做加法,而不是一个循环。
def Bitwise_add(a,b):
if b == 0:
return a
else :
return Bitwise_add(a^b , (a&b) << 1)
在这段代码中,a^b 是_和的表达式_,(a&b) << 1 是移位后的_携带表达式_。所以它被直接作为输入传递给递归函数。当进位表达式变成0 ,即b 变成0 ,递归循环停止。
位加法的时间和空间复杂度
该算法的时间复杂度为O(N),其中N是数字中的比特数。该算法的空间复杂度为O(1)。
给定一个数字M,比特数N等于logM。所以,两个数字M的相加不是一个恒定时间的O(1)操作。它需要log(M)时间。对数的基数是2。
总结
位操作是任何编程语言的一个组成部分,对它们有一个很好的理解将帮助你成为一个更好的程序员。通过OpenGenus的这篇文章,你一定对使用位操作的加法有了深刻的认识。