msp430中如何连续对位进行取反_位运算符与(&)、或(|)、异或(^)、非(~)、左移(<<)、右移(>>)、右移补零(>>>)如何选择?...

点击上方"程序员的成长之路"选择"置顶或星标" 你关注就是我关心的! d55f9530ec8800f47f16142895e0e6af.png 「 预计阅读 6 分钟 」

上一篇:消息队列 ActiveMQ 、RocketMQ 、RabbitMQ 和 Kafka 如何选择?

正文


位运算符 位:二进制简称“位”,是二进制计数系统中表示小于 2 的整数符号,一般用 1 或 0 表示,是具有相等概率的两种状态中的一种。二进制的位数可表示一个机器字的字长,一个二进制位包含的信息量称为 1 bit。( 摘自百度百科)位运算符用来对二进制位进行操作,Java中提供了如下所示的位运算符( 操作数只能为整型和字符型数据):

& 按位与

|  按位或

^ 按位异或

~ 按位取反

除 ~ 以外,其余均为二元运算符。

Java 数据类型

Java整型数据类型有:byte、char、short、int、long。要把它们转换成二进制的原码形式,必须明白他们各占几个字节。

      数据类型                           所占位数

      byte                                      8

      boolean                                8

      short                                   16

      int                                       32

      long                                    64

      float                                    32

      double                                64

      char                                    16

int 类型占 4 个字节(byte)  

一个字节 = 8bit(位)  

一个 int 类型的数值占 32bit(位)

二进制

int i = 123;  

10 进制 123 转为二进制后等于:1111011

完整补位后:00000000 00000000 00000000 01111011 tips: 全文使用的二进制为 32 位。 原码、反码和补码 二进制的最高位为符号位,1 表示负数,0 表示整数,其余位表示数的绝对值。123 转为二进制补齐后为:00000000 00000000 00000000 01111011,这是 123 的原码。-123 的原码:100000000 00000000 00000000 01111011反码:正数的反码和原码相同,负数的反码为原码除最高位外取反(0 变 1,1 变 0)。补码:正数的补码和原码相同,负数的补码为原码除最高位外取反 +1。 正数对比123 的原码:00000000 00000000 00000000 01111011123 的反码:00000000 00000000 00000000 01111011123 的补码:00000000 00000000 00000000 01111011

负数对比

-123 的原码:10000000 00000000 00000000 01111011-123 的反码:11111111 11111111 11111111 10000100-123 的补码:11111111 11111111 11111111 10000101

已知补码求原码

最高位如果是 1 的话(负数),那么除了最高位之外的取反,然后加 1 得到原码。

最高位如果是 0 的话(正数), 不变,正数的补码就是它的原码。

在计算机系统中数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。(摘自百度百科)

打个比方:2-1是怎么计算的?

计算公式:2-1=2+(-1);

 2 的补码:00000010

-1 的补码:11111111

结果 0 00000001,最高位溢出(0)丢弃, 2-1 = 1。

关于原码、反码和补码的详细解释,可看这篇: https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html

& 按位与

&:如果相对应位都是 1,则结果为 1,否则为 0。

int A = 60;

int B = 13;

A & B = 12 ,即 00001100(省略了前面三组 00000000)

如何得到 12 的呢?

60 的补码为:00111100(省略了前面三组 00000000)

13 的补码为:00001101(省略了前面三组 00000000)

按位与后值为:00001100(省略了前面三组 00000000)

将其转换为十进制:12

在 boolean 类型的值上用法也如下:

1e510941d4acb514eda5944de96c3e5b.png

| 按位或

|:如果相对应位都是 0,则结果为 0,否则为 1。

继续使用上面的例子:

int A = 60;

int B = 13;

A | B = 61 ,即 00111101(省略了前面三组 00000000)

如何得到 61 的呢?

60 的补码为:00111100(省略了前面三组 00000000)

13 的补码为:00001101(省略了前面三组 00000000)

按位或后值为:00111101(省略了前面三组 00000000)

将其转换为十进制:61 

在 boolean 类型的值上用法也如下:

cb64e5e5e5b6994c32c28bdf10ea6550.png

^ 按位异或

^:如果相对应位值相同,则结果为 0,否则为 1。

继续使用上面的例子:

int A = 60;

int B = 13;

A ^ B = 49 ,即 00110001(省略了前面三组 00000000)

如何得到 49 的呢?

60 的补码为:00111100(省略了前面三组 00000000)

13 的补码为:00001101(省略了前面三组 00000000)

按位异或后值为:00110001(省略了前面三组 00000000)

将其转换为十进制:49 

在 boolean 类型的值上用法也如下:

0e810008dfe2de8a69ff6870aad1a33c.png

~ 按位取反

~:按位取反运算符翻转操作数的每一位,即 0 变成 1 ,1 变成 0。

继续使用上面的例子:

int A = 60;

~A = -61 ,即 11000011(省略了前面三组 11111111)

如何得到 -61 的呢?

60 的补码为:00111100(省略了前面三组 00000000)

按位取反后值为:11000011(省略了前面三组 11111111)

将其转换为十进制:-61

<

<在低位补 0)。

int A = 60;

A << 2 = 240 ,即 11110000(省略了前面三组 00000000)

如何得到 240 的呢?

60 的补码为:00111100(省略了前面三组 00000000)

按位左移 2 位后为:11110000(省略了前面三组 00000000)

转换为十进制为:240

左移运算符,num << 1,相当于 num 乘以 2(每左移一位就相当于乘以一个 2)

>> 按位右移运算符

>>:按位右移运算符。左操作数按位右移右操作数指定的位数(如果该数为正数,则高位补 0 ,若为负数,则高位补 1)。

int A = 60;

A >> 2 = 15 ,即 00001111(省略了前面三组 00000000)

如何得到 15 的呢?

60 的补码为:00111100(省略了前面三组 00000000)

按位右移 2 位后值为:00001111(省略了前面三组 00000000)

转换为十进制为:15

右移运算符,num >> 1,相当于 num 除以 2(每右移一位相当于除以一个 2)。

>>> 按位右移补零操作符

>>:按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充(忽略符号位)。

正数 >>> 的结果和 >> 一样,负数则天差地别,故下面例子为负数:

int A = -2;

-2 的补码为:11111110(省略了前面三组 11111111)

负数按位右移

A >> 1 = -1 ,即 11111111(省略了前面三组 11111111)

负数按位右移补零

A >> 1 = 2147483647

-2 补码:11111111 11111111 11111111 11111110

右移 1 位:_1111111 11111111 11111111 11111111

右移 1 位之后,最后一个 0 被覆盖掉,符号位空了一位(下划线_处),按照规则,忽略符号位补零,那么第一位(符号位)就是 0 了。

补零后:011111111 11111111 11111111 11111111

转换成十进制数为:2147483647 。

注意:不存在无符号 <<< 运算符。

由于数据类型所占字节是有限的,而位移的大小却可以任意大小,所以可能存在位移后超过了该数据类型的表示范围,于是有了这样的规定:

如果为int数据类型,且位移位数大于32位,则首先把位移位数对32取模,不然位移超过总位数没意义的。所以4>>32与4>>0是等价的。

如果为long类型,且位移位数大于64位,则首先把位移位数对64取模,若没超过64位则不用对位数取模。

如果为byte、char、short,则会首先将他们扩充到32位,然后的规则就按照int类型来处理。

位运算有什么用

位运算到底有什么用途或者有哪些场景可以应用到它?因为位运算的运算效率比直接对数字进行加减乘除高很多,所以当出现以下情景且对运算效率要求较高时,可以考虑使用位运算。(源码用位运算)不过实际工作中,很少用到它,我也不知道为什么很少有人用它,我想应该是它比较晦涩难懂,如果用它来进行一些运算,估计编写的代码可读性会不强,毕竟我们写的代码不仅仅留给自己一个人看。1.  判断 int 型变量 a 是奇数还是偶数        a&1  = 0 偶数     a&1 =  1 奇数2.  求平均值,比如有两个 int 类型变量 x、y,首先要求 x+y 的和,再除以 2,但是有可能 x+y 的结果会超过 int 的最大表示范围,所以位运算就派上用场啦。      (x&y)+((x^y)>>1);3.  对于一个大于 0 的整数,判断它是不是2的几次方    ((x&(x-1))==0)&&(x!=0);4.  比如有两个 int 类型变量 x、y,要求两者数字交换,位运算的实现方法:性能绝对高效    x ^= y;    y ^= x;    x ^= y;5. 求绝对值    int abs( int x )   {     int y ;     y = x >> 31 ;    return (x^y)-y ;        //or: (x+y)^y   }6.  取模运算,采用位运算实现:     a % (2^n) 等价于 a & (2^n - 1)7.  乘法运算   采用位运算实现     a * (2^n) 等价于 a << n8.   除法运算转化成位运算      a / (2^n) 等价于 a>> n9.   求相反数      (~x+1)10  a % 2 等价于 a & 1等等,当然还有牛人使用位运算来实现权限控制,加密技术,里面的奥秘深不可测啊!

旁白:文章写到一半差点魔怔,在它(魔怔)的边缘疯狂摩擦QAQ...

如果你觉得文章不错,欢迎在看、转发、赞赏一条龙,你的支持就是我最大的动力。

2c492233baf7d3b6871d906f3a63cb36.gif

往期精彩回顾

信不信由你,一款秒级定位线上问题的神器!

接私活必备的10个开源项目!

在 Spring Boot 中,如何干掉 if else!

收藏了!7 个开源的 Spring Boot 前后端分离优质项目

Spring Boot + Vue + Shiro 实现前后端分离、权限控制

9c6a21fd714ba9093d06bfee46f86c5e.png

写留言

朕已阅 c59a181fb7342eb9db77c43c8a521ba0.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值