如何使用位运算进行比较

416 阅读6分钟

Comparison using bitwise operations

在这篇文章中,我们已经探讨了如何使 **通过位操作进行比较(等、大、小)。**的概念,以及位操作的基本概念和它们的例子。

内容表

  1. 什么是位操作?

  2. 使用位运算来比较两个操作数
    (a) 检查两个操作数是否相等
    (b) 检查哪个操作数的值小/大

  3. 时间和空间的复杂性

我们现在就开始吧。

什么是位操作?

在计算机环境中,位操作是指在位数组、位字符串或位整数的单个位(0或1)上进行最低级别的操作。

这是一个相当简单、高效和快速的操作,因为它是一个片上操作,所以被处理器直接支持。

位操作通常是双操作指令,这意味着它们至少需要两个操作数/变量/值作为输入,以产生正确的输出。

一些常用的位操作符如下。

位操作符NOT (~)

NOT是一个单数运算符(单操作数),对操作数的每个单独的位进行补足/否定/反转。

X~X
01
10

位数与 (&)

AND是一个二进制运算符,它对两个操作数的各个位进行比较,当且仅当两个位都是1时输出1,否则输出为0。

XYX & Y
000
010
100
111

位数运算 OR (|)

OR是一个二进制运算符,对两个操作数的各个位进行比较,如果被比较的任何一个位是1,则输出1,否则输出为0。

XYX │ Y
000
011
101
111

位数XOR (^)

XOR是一个二进制运算符,它对两个操作数的各个位进行比较,如果被比较的位不同,则输出1,否则输出为0。

XYX ^ Y
000
011
101
110

使用位操作来比较两个操作数

如果你要比较两个操作数而不直接使用比较运算符怎么办?

嗯,不用担心,因为即使不使用比较运算符,也可以进行大部分的比较。

我们将对两个操作数进行比较,以检查以下情况:
(a) 检查两个操作数是否相等
(b) 检查哪个操作数的值小/大

(a) 检查两个操作数是否相等

我们可以通过使用XOR运算符来检查两个给定值是否相等。如果两个数字相等,那么它们的位数XOR结果总是为0。

例如:
在十进制中,a = 9 & b = 9 在
二进制中,a = 1001 & b = 1001 a ^ b =
1001 ^ 1001 a ^ b =
0000 a ^ b =
0(十进制)
因此,a = b。

让我们看一下python语言中的一个工作实例。

def bitCheckEqual(x, y):
    return True if not x ^ y else False
    
print(bitCheckEqual(16, 61))

上面的代码产生了以下输出。

False

这段代码非常简单,并且做了它应该做的事情,然而,请记住,你只能将整数值分享给**bitCheckEqual()**函数,否则你会遇到一个错误,因为位操作一般只支持整数值。

(b) 检查哪个操作数的值小/大

我们也可以通过使用位操作符来检查两个给定值之间哪个值更小/更大。我们可以通过执行以下步骤来做到这一点。

  1. 在两个给定值上使用XOR运算符,找出它们之间不同的位。
  2. 现在我们必须确定不同的最重要的位(MSB)(MSB是指给定数字的最左边的位)。这可以通过使用位数OR位数和右移运算符来完成。
  3. 进行检查,看MSB属于哪个值。
    根据这个检查,返回最后的答案。如果一个值不包含MSB,那么它就是较小的值,我们可以简单地返回它,否则就返回其他值,因为没有其他选择。这个操作可以通过使用位元和和位元XOR运算符来完成。

例如:
在十进制中,a = 9 & b = 5 在
二进制中,a = 1001 & b = 101 让MSB
= a ^ b MSB =
1001 ^ 101 ∴ MSB
= 1100

明显,比特在两个地方不同。
现在让我们确定第一个MSB位。
MSB = MSB | (MSB >> 1) MSB =
1100 | (1100 >> 1) MSB = 1100
| 110 MSB = 1110
∴ MSB =
14 (十进制形式)

我们将重复同样的步骤,更新我们对MSB进行右移的值,分别为2、4、8和16。
执行这些步骤,我们得到MSB的最终值为1111(二进制)和15(十进制)。

现在,我们必须通过将MSB右移1来减少MSB的值,然后用它减去自身。

现在,MSB = MSB - (MSB >> 1) MSB =
1111 - (1111 >> 1) MSB = 1111
- 111 MSB = 1000

∴MSB = 8
(十进制)

现在用MSB对两个给定值中的任何一个进行比特操作,然后用MSB对该值进行XOR操作。根据这个操作得出的值,将最终答案返回给用户。
为了我们的例子,让我们在MSB和y之间进行AND操作,然后在该值和MSB之间进行XOR。

(b & MSB) ^ MSB (
101 & 1000) ^ 1000 0 ^
1000 1000 =
8 (十进制形式)

由于该值不是0,这意味着b是两者中较小的值,所以我们可以简单地返回b作为我们的最终答案。
要找出两者中较大的值,我们可以简单地翻转条件并在这里返回a的值。

让我们看一下用python语言找出较小元素的工作实例。

def bitCheckLess(x, y):
    msb = x ^ y
    msb |= (msb >> 1)
    msb |= (msb >> 2)
    msb |= (msb >> 4)
    msb |= (msb >> 8)
    msb |= (msb >> 16)
    msb = msb - (msb >> 1)
    return x if (not((y & msb) ^ msb)) else y
    
    
print(bitCheckLess(9, 5))

上面的代码产生了以下输出。

5

对于寻找更大的值,除了if条件部分,代码将是类似的。下面是一个同样的例子。

def bitCheckLarge(x, y):
    msb = x ^ y
    msb |= (msb >> 1)
    msb |= (msb >> 2)
    msb |= (msb >> 4)
    msb |= (msb >> 8)
    msb |= (msb >> 16)
    msb = msb - (msb >> 1)
    return x if ((y & msb) ^ msb) else y
    
    
print(bitCheckLarge(12314, 12315))

上面的代码产生了以下输出。

12315

再一次,这两段代码都做了它们应该做的事情,尽管它们使用的操作比我们之前的算法多得多。请记住,你只能将整数值分享给bitCheckLess()bitCheckLarge()函数,否则你会遇到一个错误,因为位操作一般只支持整数值。

时间和空间的复杂性

**时间的复杂性。**在比较函数中进行的比较实际上取决于输入数字的位数。尽管顺时针操作的速度相当快,但这将使我们算法的整体时间复杂度为 **O(n)**,其中n=输入数字的位数。

**空间复杂度。**除了msb变量外,没有额外的空间被使用,因此我们算法的整体空间复杂度将是 **O(1)**.

通过OpenGenus的这篇文章,你一定对使用位操作的比较法有了完整的认识。