数据类型溢出处理机制以及位运算原理

Posted 客官不爱喝酒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据类型溢出处理机制以及位运算原理相关的知识,希望对你有一定的参考价值。

万丈高楼平地起:基础知识真的很重要,如果你不想成为一个只会调api的程序员的话,那么基础知识一定要扎实,有时候虽然这些东西不常用,但是你遇到了就无法解决,如果那你不会二进制转换,那么原码,反码,补码之间的转换,你就看不懂,原码,反码,补码之间的转换不会那么你将不会位运算,如果不会位运算那么你将看不懂HashMap里面的位运算操作,并且很多算法也会用到这些知识,所以该文章从基础一步一步讲解。

二进制的表示方式为:只有0和1

如果这里以1个字节为例,一个字节=8位
00000001:这就是一个正数对应的二进制
最左边的第一位为符号位:0表示正数,1表示负数
所以说:虽然1字节有8位,但是除去符号位,也就剩下7位来表示数据了。

1.二进制与十进制的互转

无论是正数还是负数在计算机中表示的方式都为补码

二进制转十进制(此处以1个字节为例,1个字节表示的就是8个0或1的数)

java中的byte占1个字节,也就是最多只能存储8位,表示的范围就是:-128~127

方式1: 将二进制数从右往左写,符号位不用管,但是如果是负数,最后需要补上符号位,从首位往后写,正不够补0,负数补1,将1对应的值加起来。
如:二进制码为:00111000转为十进制就是:56 如下图所示:大家可以多举几个例子进行验证,如果说128不够用怎么办?依次进行递增嘛。

在这里插入图片描述
如果是int类型的就是占4个字节,也就是说能储存32位的数据,除去符号位,剩下31位表示数据,所以也可以说是int的范围为:-2^31 ~ 2^31

方式2:数码乘权,展开相加

在这里插入图片描述

十进制转二进制

利用短除法:将该数除2,取余数,直到该数不能被整除为止,然后逆序的方式写出余数就是该10进制数对于的2进制数。

在这里插入图片描述

2.二进制的加减法

二进制加法

注意:我们平常用的 4+6=10 用的是10进制的运算规则。十进制的运算规则为:逢10进1,那么二进制对应的运算规则就为:逢2进1

举个例子:10进制的加法

在这里插入图片描述

二进制例子:就按照逢2进1就好了,在复杂的也是如此

在这里插入图片描述

二进制减法

十进制的减法是借1当10,那么二进制对应的减法运算规则就是借1当2

看个例子:
在这里插入图片描述

3.二进制的原码,反码,补码之间的转换

无论是正数还是负数在计算机中表示的方式都为补码

正数的原码,反码,补码都是不变的,也就是该10进制数对应的,二进制码,所以有点人会说:计算机中正数是以原码进行计算,负数是补码进行计算和(无论是正数还是负数在计算机中表示的方式都为补码)这个说法是一致的

原码

原码就是对应的二进制表示方式,高位为符号位,也就是左边第一位

1对应的二进制为:00000001
127对应的二进制为:01111111
0对应的二进制为:000000000
-128对应的二进制为:10000000
-127对应的二进制为:10000001

可以看到00000000表示的就是0,按照上面的理论100000000也表示0,而且是负0,但是不可能出现两个0呀,而且是一个正0一个负0,所以呀就规定10000000表示为-128,所以说,正数的表示就比负数少了个1,就少在这个负0上。

注意:在运算溢出时,最大数加1就为最小值,最小值加1就为最大值
在这里插入图片描述

反码的表示方式:在原码的基础上,符号位不变,按位取反,也就是对应的0变1,1变0

例子:

补码的表示方式:原码取反再加个1(符号位不变),也可以说成是:反码+1

在这里插入图片描述

4.位运算

按位与(&):两位全为1,结果为1,其余位为0

例子:6&2=2;大家可以使用代码进行验证
在这里插入图片描述我这里替大家验证一次,往后的我就不进行验证了

在这里插入图片描述

按位或(|):两位一个结果为1,结果就为1,其余的为0

例子:6|2=6

在这里插入图片描述

按位异或(^):两个位其中一位为1,一位为0结果为1,其余情况为0

例子:6^2=4
在这里插入图片描述

按位取反:该数的补码+1的结果填个负号,公式为:~x=-(x+1);

例子:~6=-(6+1)=-7
在这里插入图片描述

5.位移运算

为什么会有位移运算?

因为计算机底层其实就是通过位移的操作进行计算的,直接使用位移运算会变我们的表达式计算会快很多,如djk源码中的HashMap就大量的使用了位移运算。

如图所示
在这里插入图片描述在这里插入图片描述

你是否在想?为什么不直接写为16呢?而是要写为1<<4 难道是写源代码的人喜欢装x?喜欢搞一些你看不懂的,然后觉得代码高大上?其实并不是,因为这样写运算的时候会快一些,假设你不懂二进制,这些基础知识,你根本都看不懂别到底写的什么?也也写不出高性能的代码,而且很多算法也是需要这些基础知识的。

正数右移:左边自动补0,右边移除舍去位,每向右移动一位,就想当于除以2(舍去小数位)

例子:10>>2=2 (10/2/2=2)
在这里插入图片描述

负数右移:由于二进制的首位为符号位,负数在右移过程中,为了保持负数的特性,左边就会自动补1,而不是补0了,补码高位为1,移动x位,按位取反加1即可,符号位不变

例子:-10>>2=-3
好像貌似没有那么复杂,暂时我还不知道有更简便的方法,而且我在位移的时候并没有补1,因为我怕大家迷惑。
在这里插入图片描述看下代码编译结果:
在这里插入图片描述

正数左位移:左边自动补0,右边移除舍弃位,每向左移动1位,就相当于乘以2

例子:10<<2=40(1022=40)

在这里插入图片描述

负数左位移:右边自动补1,左边移除舍去位,每向左移动1位,就相当于乘以2

其实和正数左位移差不多,只是计算结果为负数而已
也就是说:n<<x=-(n*2^x)

-10<<2=-40

在这里插入图片描述
来再看一个:
在这里插入图片描述

无符号右移:所谓的无符号位移,就是不考虑符正负,左边一律补0

2>>>1=1

没有无符号左移啊,这个没有哈,不要闹笑话哦。右移后高位是空出来的,对于空出来的高位,就需要去考虑补0还是补1,而左移后高位时被舍弃掉的,根本不需要“补位”一说。这也就解释了为什么右移有“有无”符号之别,而左移却没有,因为根本就没有必要。

以上是关于数据类型溢出处理机制以及位运算原理的主要内容,如果未能解决你的问题,请参考以下文章

20179223《Linux内核原理与分析》第十一周学习笔记

重学计算机计组D3章:运算方法与运算器

计算机组成原理——加减运算 & 溢出判断

计算机组成原理——加减运算 & 溢出判断

2017-2018-2 20179207 《网络攻防技术》第十周作业

定点数运算及溢出检测