在这篇文章中,我们将看到如何使用位运算符>> ,而不是使用常规的除法运算符/ ,或乘法运算符* ,或模运算符% ,来除掉一个数字。
内容表。
- 除法简介
- 所需的位操作的回顾
- 使用左移运算符的除法
- 时间和空间的复杂性
- 总结
现在我们将探讨顺位运算的算法。
除法简介
因此,这里的任务是将一个给定的数字与另一个数字相除,并返回底限值,即只是小数商,但我们应该使用位运算符,而不是像* / % 这样的常规运算符来除数。
让我们通过一个例子来看看,考虑96 和7
96 / 7 = 13.71 ,其底限值为
13
所以,我们需要写一个函数来做这件事,但要使用逐位运算符。
回顾一下所需的位操作
在我们进入问题之前,让我们快速回顾一下位数移位运算符,因为我们要用它来解决这个问题。
比特左移运算符
左移运算符用于将给定的数字向左移动一定数量的比特,如下图所示。
但是当我们左移时会发生什么呢?让我们仔细看看。
我们知道二进制数字系统是基于2的幂。看一下表格,我们可以看到下面每个比特的位置权重是前一个比特的两倍,即它的幂增加了1。同样,当一个数字被向左推了n位时,意味着该数字被乘以2的n次方。
如图所示。25 << 1 = 50 (25 * 2 power 1)
25 << 3 = 200 (25 * 2 power 3)
因此,一般来说,如果你把一个数字向左移了n位,它就会被乘以2的n次方。
位向右移运算符
右移运算符将比特向右移动。这意味着它的作用与左移运算符完全相反,即每当我们将一个数字向右移1位时,它就将该数字除以2。
例子96 >> 1 = 48
现在,我们已经对移位运算符有了足够的了解,让我们用它们来除以一个数字和另一个数字。
使用左移运算符的除法
让我们把两个数字a = 96 和b = 7 。当我们用a 除以b 时,我们是在计算b 的多少倍等于a 或者b 的多少倍可以装入a 。在这种情况下,我们可以把13个b's放在a ,即a / b = 13 (注意:这里我们只计算下限值)。
我们知道,每个数字都可以表示为2的幂的总和,而且当我们把一个数字向左移动n位时,它将被乘以2 power n 。因此,我们要做的是将除数b 向左移动,并检查它是否小于或等于红利a 。如果它小于或等于红利,我们就从红利中减去它,然后把2 power n 的值加入我们的答案中。这样做,我们得到的答案是2的幂的总和,这将使我们得到所需的商。
这里我们选择31,因为一般来说,整数数据类型的大小是32位,即从0开始一直到31。
操作步骤
-
首先,设置答案变量,即商为
0。 -
检查是否有任何一个数字是负数,并将其存储在一个单独的变量中。
-
使两个数字都为正数。
-
从
n = 31最重要的位开始,循环到n = 0最不重要的位。-
检查除数的移位
n,是否小于或等于红利。- 如果是,从红利中减去它,然后更新红利。
- 在答案中加入
2幂n
( 注意:在这里,每次条件为真的时候,红利都会被减少到提醒的位置。)
-
-
最后,用第2步的结果检查商应该是正数还是负数后,返回商。
def bit_div(a,b):
ans = 0 # the quotient is intialized
neg = a < 0 or b < 0 # Checking if one of the numbers is negative
a = abs(a) # making sure both the numbers
b = abs(b) # are positive
for i in range(31,-1,-1): # starting our loop
if b << i <= a : # checking if b multiplied by 2**i is <= a
a -= b << i # subtracting b << i from a
ans += 1 << i # adding 2 power i to the answer
# and finally checking if the output should be negative and returning it
return ans if neg == 0 else -1 * ans
现在,让我们来分解一下这段代码。
我们得到两个数字a 和b 作为输入,然后我们启动一个变量ans 来存储我们的最终答案,即商。然后我们检查其中一个数字是否为负数,但我们为什么要这样做呢?因为,如果其中一个数字是负的,商也将是负的,但是,如果两个数字都是正的,或者都是负的,答案将是正的。
然后我们取两个数字的绝对值,使它们都是正数。然后我们开始我们的循环。我们从31 _最重要的位_开始,因为如前所述,一个整数的大小是32位,然后遍历到0 最小有效位。在每个迭代过程中,我们检查b << i ,即b乘以2 ,再乘以i ,是否小于或等于a ,即股息。如果是真的,我们从红利a 中减去b << i ,并更新它,然后将等于2 power i 的1 << i 加到答案变量ans 。我们这样做直到循环到达0 。
最后,我们使用变量neg 的值检查答案是负数还是正数,并以正确的形式返回。
让我们通过一个例子来了解一下,以获得更好的理解。
考虑a = 96 和b = 7
所以控制流程是这样的。
ans = 0neg = 0即为假(因为96或7都是正数)。- 由于这两个数字都是正数,所以绝对值与数字相同。
- 那么循环就从
i = 31 - 直到
i = 4,因为7 << i大于96,所以_if语句_没有被执行。 - 当
i = 3,7 << i的值是56,小于96,因此它进入了if语句。a = 40(a = a - b << ii.e.a = 96 - 56)ans = 8(ans += 1 << ii.e.ans = 0 + 8)
- 现在,
i = 2,7 << i的值是28,小于40,当前a。a = 12ans = 12i.e.8 + 4
- 现在,
i = 1再次7<<i(14) 大于a即12所以不执行。 - 然后
i变成0a = 5ans = 13i.e.12 + 1
- 循环结束,我们在
a的提醒5,在ans的商13。因此,我们最后返回商ans。
时间和空间复杂度
这个算法的时间复杂度将是O((log a)^2),其中a是红利。
这是因为每次左移操作都需要O(log a)的时间。简而言之,除法是基于乘法运算的,基数乘法算法的时间复杂度就是除法运算的时间复杂度。
该算法的空间复杂度为O(1)。
总结
位运算符是任何编程语言的重要组成部分之一。它们在密码学、散列函数、计算机图形等方面有很多应用。因此,拥有一个良好的位操作流程对你的编程技能来说总是一笔财富。
通过OpenGenus的这篇文章,你一定对使用位操作的除法有了完整的认识。请欣赏。