Matlab中按位运算

目录

数值表示

用逻辑运算符进行位掩码

移位

写入位

读取连续位

读取非连续位


       如何在 MATLAB® 中使用按位运算来操作数字的位。大多数现代处理器直接支持位运算。在许多情况下,以这种方式操作数字的位比执行除法或乘法等算术运算更快。

数值表示

       任何数值都可以用位来表示(也称为二进制位)。数值的二进制(即基数为 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 = 0b111
b = uint8
    7

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

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

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

  3. 最后,对结果加 1:11111000。

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

n = 0b11111000s8
n = 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。

         上述操作有时写作 A<<N(左移)和 A>>N(右移),但 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
dec
dec = 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

  • 5
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值