按位运算 您所在的位置:网站首页 二进制数除以4 按位运算

按位运算

2023-06-02 15:04| 来源: 网络整理| 查看: 265

数值表示

任何数值都可以用位来表示(也称为二进制位)。数值的二进制(即基数为 2)形式包含 1 和 0,以此表示数值中都存在 2 的哪些次幂。例如,7 的 8 位二进制形式是

00000111

8 个位的集合也称为 1 个字节。在二进制表示中,位从右向左计数,因此该表示中的第一个位是 1。此数值表示 7,因为

22+21+20=7.

当您在 MATLAB 中键入数值时,它假设数值为双精度(64 位二进制表示)。但是,您也可以指定单精度数(32 位二进制表示)和整数(有符号或无符号,从 8 到 64 位)。例如,要存储数值 7,最节省内存的方法是使用 8 位无符号整数:

a = uint8(7)a = uint8 7

您甚至可以直接使用前缀 0b 后跟二进制数字来指定二进制形式(有关详细信息,请参阅十六进制和二进制值)。MATLAB 以位数最少的整数格式存储数值。您只需指定最左边的 1 和它右边的所有位,而不必指定所有位。该位左边的位是无效零。因此数值 7 是:

b = 0b111b = uint8 7

MATLAB 使用 2 的补码存储负整数。以 8 位有符号整数 -8 为例。要找到该数值的 2 的补码位模式,请执行以下操作:

首先找到该数值对应的正数 8 的位模式:00001000。

接下来,翻转所有位:11110111。

最后,对结果加 1:11111000。

得到的 11111000 是 -8 的位模式:

n = 0b11111000s8n = int8 -8

MATLAB 并不主动显示数值的二进制格式。为此,您可以使用 dec2bin 函数,该函数会返回正整数的二进制数字字符向量。同样,此函数只返回不包含无效零的位。

dec2bin(b)ans = '111'

您可以使用 bin2dec 在这两种格式之间切换。例如,您可以使用以下命令将二进制数字 10110101 转换为十进制格式

data = [1 0 1 1 0 1 0 1]; dec = bin2dec(num2str(data))dec = 181

cast 和 typecast 函数也可用于不同数据类型之间的切换。这些函数是相似的,但它们在如何处理数值的底层存储方面有所不同:

cast - 更改变量的基础数据类型。

typecast - 转换数据类型而不更改基础位。

由于 MATLAB 不直接显示二进制数的位,您在进行按位运算时必须注意数据类型。有些函数以字符向量形式返回二进制数字 (dec2bin),有些函数返回十进制数 (bitand),还有一些函数返回由位本身组成的向量 (bitget)。

用逻辑运算符进行位掩码

使用 MATLAB 中的一些函数,您可以对以等长二进制表示的两个数值中的位执行逻辑运算,此种运算称为位掩码:

bitand - 如果两个位均为 1,则结果位也是 1。否则,结果位为 0。

bitor - 如果任一位是 1,则结果位也是 1。否则,结果位为 0。

bitxor - 如果位不同,则结果位为 1。否则,结果位为 0。

除了这些函数之外,您还可以使用 bitcmp 进行按位补码,但这是一元运算,一次只能翻转一个数值中的位。

位掩码的一个用途是查询特定位的状态。例如,如果对二进制数 00001000 进行按位 AND 运算,您可以查询第四个位的状态。然后,您可以将该位移至第一个位置,以便 MATLAB 返回 0 或 1(下一节将更详细地说明位移)。

n = 0b10111001; n4 = bitand(n,0b1000); n4 = bitshift(n4,-3)n4 = uint8 1

按位运算有时可以发挥意想不到的作用。例如,以下是数值 n=8 的 8 位二进制表示:

00001000

8 是 2 的幂,因此它的二进制表示只包含一个 1。现在考虑数值 (n-1)=7:

00000111

由于减去了 1,从最右边的 1 开始的所有位都会翻转。因此,当 n 是 2 的幂时,n 和 (n-1) 的对应位始终不同,使得按位 AND 返回零。

n = 0b1000; bitand(n,n-1)ans = uint8 0

但是,如果 n 不是 2 的幂,则最右边的 1 表示 20 位,因此 n 和 (n-1) 除了 20 位之外,其他位都相同。在这种情况下,按位 AND 返回一个非零数值。

n = 0b101; bitand(n,n-1)ans = uint8 4

受上述运算启发,我们可以编写一个简单的函数对给定的输入数值执行位运算,以判断它是否为 2 的幂:

function tf = isPowerOfTwo(n) tf = n && ~bitand(n,n-1); end

使用短路 AND 运算符 && 检查以确保 n 不为零。如果为零,则该函数不需要计算 bitand(n,n-1) 即可知道正确答案是 false。

移位

由于按位逻辑运算比较两个数值中对应的位,因此,能够按需移位以便于比较对应位就显得非常重要。您可以使用 bitshift 执行此操作:

bitshift(A,N) 将 A 的位向左移动 N 位。这等效于将 A 和 2N 相乘。

bitshift(A,-N) 将 A 的位向右移动 N 位。这等效于将 A 除以 2N。

上述操作有时写作 AN(右移),但 MATLAB 没有将 运算符用于此目的。

当数值的位发生移动时,数值会从末尾丢弃一些位,并引入 0 或 1 来填充新腾出的空间。当您向左移动位时,右端发生位填充;当您向右移动位时,左端发生位填充。

例如,如果将数值 8(二进制:1000)右移一位,则得到 4(二进制:100)。

n = 0b1000; bitshift(n,-1)ans = uint8 4

同样,如果将数值 15(二进制:1111)左移两位,则得到 60(二进制:111100)。

n = 0b1111; bitshift(15,2)ans = 60

当您移动负数的位时,bitshift 会保留有符号位。例如,如果将有符号整数 -1(二进制:11111101)向右移动 2 位,则得到 -1(二进制:11111111)。在这些情况下,bitshift 在左端填充 1 而不是 0。

n = 0b11111101s8; bitshift(n,-2)ans = int8 -1 写入位

您可以使用 bitset 函数来更改数值中的位。例如,将数值 8 的第一个位更改为 1(相当于将该数值加 1):

bitset(8,1)ans = 9

默认情况下,bitset 将位翻转为 on 或 1。您可以选择使用第三个输入参数来指定位值。

bitset 不会一次更改多个位;要更改多个位,您需要使用 for 循环。因此,您更改的位可以是连续的,也可以是非连续的。例如,更改二进制数 1000 的前两位:

bits = [1 2]; c = 0b1000; for k = 1:numel(bits) c = bitset(c,bits(k)); end dec2bin(c)ans = '1011'

bitset 的另一个常见用途是将二进制数字向量转换为十进制格式。例如,使用循环来设置整数 11001101 的各个位。

data = [1 1 0 0 1 1 0 1]; n = length(data); dec = 0b0u8; for k = 1:n dec = bitset(dec,n+1-k,data(k)); end decdec = uint8 205 dec2bin(dec)ans = '11001101' 读取连续位

位移的另一个用途是隔离位的连续部分。例如,读取 16 位数值 0110000010100000 中的最后四位。前面提到,最后四位位于二进制表示的左端。

n = 0b0110000010100000; dec2bin(bitshift(n,-12))ans = '110'

要隔离该数值中间的连续位,可以结合使用位移和逻辑掩码。例如,要提取第 13 位和第 14 位,可以向右移动 12 位,然后用 0011 对所得的 4 位进行掩码。由于 bitand 的输入必须为相同的整数数据类型,您可以使用 0b11u16 将 0011 指定为无符号 16 位整数。如果没有 -u16 后缀,MATLAB 会将数值存储为无符号 8 位整数。

m = 0b11u16; dec2bin(bitand(bitshift(n,-12),m))ans = '10'

读取连续位的另一种方法是使用 bitget,它从数值中读取指定的位。您可以使用冒号表示法指定要读取的几个连续位。例如,读取 n 的最后 8 位。

bitget(n,16:-1:8)ans = 1x9 uint16 row vector 0 1 1 0 0 0 0 0 1 读取非连续位

您也可以使用 bitget 从数值中读取彼此不相邻的位。例如,从 n 中读取第 5、8 和 14 位。

bits = [14 8 5]; bitget(n,bits)ans = 1x3 uint16 row vector 1 1 0


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有