java二进制运算符从左向右求值,java二进制操作计算的总结

写在前面

一直以来对二进制的操作计算不太清楚,这次找了一些资料完整地进行了一些总结。

一、进制类别和关系:

二进制,十进制,十六进制的区别和进制之间的相互转换方法(概念性的东西,可以百度)。

n位的二进制能够表示2的n次方个数,如4位的二进制可以表示十进制的0~15共16个数 。

十六进制的基数是16,数码为0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F,其中用A,B,C,D,E,F(字母不区分大小写)这六个字母来分别表示10,11,12,13,14,15。

由于十六进制的基数是2的幂,因此二进制和十六进制的转换很方便。一个二进制数,只要把它从低位到高位每4位组成一组,4个二进制位可以表示从0到15的数字,这刚好是1个16进制位可以表示的数据,也就是说,将二进制转换成十六进制只要每4位进行转换就可以了。

0011 0101 1011 1111 = 0x35BF(以0x开始的数据表示16进制) 。

MIN_VALUE = 0x80000000对应的二进制是10000000 00000000 00000000 00000000

MAX_VALUE = 0x7fffffff对应的二进制是01111111 11111111 11111111 11111111

二、移位操作

左移位<< :

/* 00000001 << 1 = 00000010 */

1 << 1 == 2

/* 00000001 << 3 = 00001000 */

1 << 3 == 8

复制代码

右移位>> :

向右移位是有符号操作符。和许多语言一样,Java使用最高位来表示数值的正负,负数的最高位永远为1。一个以1开头的二进制数移位后还将以1开头,一个以0开头的二进制数移位后还将以0开头。

/* 11111111 11111111 11111111 11110000 >> 4 = 11111111 11111111 11111111 11111111 */

0xFFFFFFF0 >> 4 == 0xFFFFFFFF

/* 00001111 11111111 11111111 11111111 >> 4 = 00000000 11111111 11111111 11111111 */

0x0FFFFFFF >> 4 == 0x00FFFFFF

复制代码

无符号右移>>> :这种移位会忽略符号位并总是用“0”来填充。

/* 10000000 00000000 00000000 00000000 >>> 1 = 01000000 00000000 00000000 00000000 */

0x80000000 >>> 1 == 0x40000000

复制代码

移位的作用

迅速求2的幂。1向左移位1位是2,移2位是4,移3位是8…… 相似的,向右移1位相当于是把该数除以2。(将一个数k移动n位,可以看做将k*2^n)

创建掩码。位掩码可用于屏蔽或者修改一个二进制数中的某些指定位。如得到00001000的掩码可以通过1 << 3得到。

三、位运算操作符

~ :按位取反,如果位为0,结果是1,如果位为1,结果是0

~1111 == 0000

~0011 == 1100

复制代码

& : 按位与,两个操作数中位都为1,结果才为1,否则结果为0

1010 & 0101 == 0000

1100 & 0110 == 0100

复制代码

^ : 按位异或,两个操作数的位中,相同则结果为0,不同则结果为1

1010 ^ 0101 == 1111

1100 ^ 0110 == 1010

复制代码

| : 按位或,两个位只要有一个为1,那么结果就是1,否则就为0

1010 | 0101 == 1111

1100 | 0110 == 1110

复制代码

位运算符的作用:

可以选择性的把一个二进制数的某位设为0,让数与一个全1但是某位为0的数相与。如,01010101 & ~(1<<2) == 01010101 & 11111011 == 01010001

四、原码, 反码, 补码:

对于一个数, 计算机要使用一定的编码方式进行存储。原码,反码,补码是机器存储一个具体数字的编码方式。

机器数和真值

机器数:一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。如,00000011 和 10000011这两个机器数分别表示+3和-3。

真值:将带符号位的机器数对应的真正数值称为机器数的真值。如,10000011其最高位 1 代表负,其真正数值是 -3而不是形式值131(10000011转换成十进制等于131)。

原码:符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值.如,[+1]原 = 0000 0001,[-1]原 = 1000 0001

因为第一位是符号位, 所以 8 位二进制数的取值范围是:[1111 1111 , 0111 1111] 即 [-127 , 127]

原码是人脑最容易理解和计算的表示方式.

反码:正数的反码是其本身,负数的反码是在其原码的基础上,符号位不变,其余各个位取反。如,[+1] = [00000001]原 = [00000001]反 / [-1] = [10000001]原 =[11111110]反

如果一个反码表示的是负数,人脑无法直观的看出来它的数值.通常要将其转换成原码再计算.

补码:正数的补码就是其本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反, 最后 +1. (即在反码的基础上 +1)

对于负数, 补码表示方式也是人脑无法直观看出其数值的。通常也需要转换成原码再计算其数值。

为何要使用反码和补码

设计简单:因为人脑可以知道第一位是符号位,在计算的时候我们会根据符号位,选择对真值区域的加减。但是对于计算机,加减乘数是最基础的运算,要设计地尽量简单。而让计算机辨别"符号位"会让计算机的基础电路设计变得十分复杂。

加法设计:可以用符号位参与运算来简化设计。根据运算法则减去一个正数等于加上一个负数, 即: 1-1=1+(-1)=0,所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单了。

原码直接符号位相加,得到的结果是错误的,因此需要使用反码和补码

反码加法:

反码加法结果的真值部分是正确的,但是在"0"这个特殊的数值上,虽然人们理解上 + 0和 -0 是一样的, 但是 0 带符号是没有任何意义的, 而且会有 [0000 0000]原和[1000 0000]原两个编码表示 0。

// 计算十进制的表达式: 1 - 1 = 0

1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

复制代码

补码加法:

1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

复制代码

这样 0 用 [0000 0000] 表示,而反码出现问题的-0则不存在了,而且可以用多余的[1000 0000] 表示 -128:

(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补

复制代码

在用补码运算的结果中,[10000000]补就是-128,但是注意因为实际上是使用以前的-0的补码来表示 -128, 所以 -128并没有原码和反码表示(对-128的补码表示[10000000]补算出来的原码是[0000 0000], 这是不正确的)

使用补码运算能够多表示一个最低数,这就是为什么8位二进制,使用原码或反码表示的范围为 [-127, +127], 而使用补码表示的范围为 [-128, 127]。

五、Integer的MIN_VALUE和MAX_VALUE

计算机存储数字是使用补码, 所以对于编程中常用到的 32 位int类型,可以表示范围是: [-2^31, 2^31-1] 因为第一位表示的是符号位,而使用补码表示时又可以多保存一个最小值。

从表示的数字总数来说,还是 2^31*2(因为正负值,所以*2)

对于正数的2^31来说,[00000000 00000000 00000000 00000000]表示了0,所以正数的最大值是2^31-1(因为一种排列一个数,数与数之间都是隔1,所以正数总数-1即正数的最大值)。

对于负数的2^31来说,[10000000 00000000 00000000 00000000]表示了最大值,所以负数的最大值是-2^31,多表示了一个数。

Integer.MAX_VALUE,即2^31-1=2147483647,最小值为-2^31=Integer.MIN_VALUE -2147483648

越界问题

Integer.MIN_VALUE-1 = Integer.MAX_VALUE:

Integer.MIN\_VALUE - 1 = Integer.MIN_VALUE + (-1)

10000000000000000000000000000000

+ 11111111111111111111111111111111[补]

---------------------------------------------------

1,01111111111111111111111111111111[补]

舍弃最高位的进位,所以得到的就是Integer.MAX_VALUE

复制代码

Integer.MAX_VALUE + 1= Integer.MIN_VALUE:

对Integer.MAX_VALUE加1,2147483648(越界了),结果是-2147483648,即是Integer.MIN_VALUE。

01111111111111111111111111111111

+ 00000000000000000000000000000001[正数补码等于本身]

---------------------------------------------------

10000000000000000000000000000000[补]

复制代码

对Integer.MIN_VALUE取绝对值:

因为值为-2147483648,绝对值2147483648超过Integer.MAX_VALUE 2147483647,所以值还是Integer.MIN_VALU。因为,Integer.MAX_VALUE=01111111111111111111111111111111,再加1为10000000000000000000000000000000,等于Integer.MIN_VALUE

四、Java中的方法

java代码里操作二进制数字的方法是使用Integer.parseInt()方法。如,Integer.parseInt(“101″,2)代表着把二进制数101转换为十进制数5。

五、参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值