众所周知,由于电路的复杂性因素,电脑中都使用二进制数,只有0和1两个数码,逢二进一,最容易用电路来表达,比如0代表电路不通,1代表电路通畅。那么,什么是二进制呢?
比如说我们所熟悉的十进制,通俗的说是由0,1,2,3,4,5,6,7,8,9这十个数字组成,如果比9再大一个数,就会进一位,高位加一,低位重置,也就是10。
再比如八进制,是由0,1,2,3,4,5,6,7这八个数组成,逢八进一,比7大一个,就会进一位,也就是10。
以此类推,二进制,就是由0和1组成,逢二进一。
因为计算机只认识二进制,所以它也压根不知道什么是加减乘除,我们之所以能用在电脑上使用计算器进行加减乘除的操作,是因为底层进行了一些位运算的操作,来达到加减乘除的目的。
位运算可以理解为就是二进制之间的操作运算,有以下几种:
(注意,在本文中,所有二进制的长度都是以字节为单位。额…计算机的存储单位分为,位:一个二进制位、字节:一个字节等于八位、字:一个字等于十六位、双字:一个双字等于32位、四字:一个四字等于六十四位)
1.按位与(&)
如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。
比如 0 1 0 1 0 0 0 1和0 0 0 0 1 0 1 1进行与运算
0 1 0 1 0 0 0 1
0 0 0 0 1 0 1 1
-------------------
0 0 0 0 0 0 0 1
运算后结果就是 0 0 0 0 0 0 0 1;
2.按位或(|)
如果两个相应的二进制位中只要有一个为1,该位的结果值为1。
比如 0 1 0 1 0 0 0 1和0 0 0 0 1 0 1 1进行或运算
0 1 0 1 0 0 0 1
0 0 0 0 1 0 1 1
-------------------
0 1 0 1 1 0 1 1
运算后结果就是 0 1 0 1 1 0 1 1;
3.按位异或(^)
若参加运算的两个二进制位值不同则为1,否则为0。
比如 0 1 0 1 0 0 0 1和0 0 0 0 1 0 1 1进行异或运算
0 1 0 1 0 0 0 1
0 0 0 0 1 0 1 1
-------------------
0 1 0 1 1 0 1 0
运算后结果就是 0 1 0 1 1 0 1 0;
4.取反(~)
~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0。
比如 0 1 0 1 0 0 0 1进行取反操作
0 1 0 1 0 0 0 1
运算后结果就是 1 0 1 0 1 1 1 0;
5.左移(<<)
整个二进制向左移动n位,高位去除;
6.右移(>>)
整个二进制向右移动n位,无符号位 高位补0,有符号位 高位 补符号位;
讲到这里可能要跟大家解释下什么是无符号和有符号:
因为计算机只能识别0和1,所以前人想出了一个办法,以最高位表示符号位(正或者负),其余位表示数值大小,这样的数就被称为有符号数,而无符号数则是所有位都用于表示数的大小。
现在,我们就来看看加减乘除在计算机内部是怎样实现的。
加法:
例如13 + 11,在计算机中13会被转成二进制 0 0 0 0 1 1 0 1 ,11则会被转成 0 0 0 0 1 0 1 1,
0 0 0 0 1 1 0 1
0 0 0 0 1 0 1 1
加--------------------
0 0 0 1 1 0 0 0
这是我们通过加法计算得到的结果,0 0 0 1 1 0 0 0 ,也就是24,但是,计算机并不会加法,只会与、或、异或等位运算,所以,我们只能通过位运算去达到加减乘除的效果。
0 0 0 0 1 1 0 1
0 0 0 0 1 0 1 1
与 --------------------
0 0 0 0 1 0 0 1
,
0 0 0 0 1 1 0 1
0 0 0 0 1 0 1 1
或 --------------------
0 0 0 0 1 1 1 1
,
0 0 0 0 1 1 0 1
0 0 0 0 1 0 1 1
异或--------------------
0 0 0 0 0 1 1 0
对比一下不难发现,异或的结果在不考虑进位的情况下,跟加法的结果是一样的,那么进位的数我们该怎么处理呢?
首先对异或的结果进行判断,判断是否存在进位,如果不存在 ,那么异或的结果就是加法的结果。
那么,怎么判断是否存在进位呢?我们观察一下不难发现,只有相同位都是1的情况下,才会存在进位,那么,对应到位运算中就是与,与运算只有相同位都是1,结果才为1。
0 0 0 0 1 1 0 1
0 0 0 0 1 0 1 1
与 --------------------
0 0 0 0 1 0 0 1
与运算后的结果是0 0 0 0 1 0 0 1,说明两个二进制位相加是存在进位的,那么,我们需要对与运算后的结果进行左移一位,因为通过计算进位后,结果本身会进一位。
0 0 0 0 1 1 0 1左移一位后的结果是0 0 0 1 0 0 1 0。
接着我们将异或后的结果,与左移后的结果再进行异或运算。
0 0 0 0 0 1 1 0
0 0 0 1 0 0 1 0
异或--------------------
0 0 0 1 0 1 0 0
异或运算后的出结果0 0 0 1 0 1 0 0,每次异或之后我们都需要判断是否存在进位。
0 0 0 0 0 1 1 0
0 0 0 1 0 0 1 0
与 --------------------
0 0 0 0 0 0 1 0
发现存在进位后,再对进位的结果左移一位,得到 0 0 0 0 0 1 0 0。
然后再将异或结果与左移后的结果进行异或运算。
0 0 0 1 0 1 0 0
0 0 0 0 0 1 0 0
异或--------------------
0 0 0 1 0 0 0 0
再与运算判断是否存在进位。
0 0 0 1 0 1 0 0
0 0 0 0 0 1 0 0
与 --------------------
0 0 0 0 0 1 0 0
存在,则进行左移操作,得到0 0 0 0 1 0 0 0。
然后,再重复上述步骤。
0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0
异或--------------------
0 0 0 1 1 0 0 0
,
0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0
与 --------------------
0 0 0 0 0 0 0 0
OK,到这终于不用进位了,上一步异或操作,就是最终的结果0 0 0 1 1 0 0 0,跟上面通过加法得到的结果是一致的。
最后总结下位运算进行加法操作的步骤:
1.对两个二进制位进行异或运算
2.对两个二进制位进行与运算,如果结果为0,则不存在进位,上一次异或运算结果就是加法的最终结果,如果存在进位,则将与运算后的结果进行左移一位。
3.对上次异或运算结果和左移结果重复步骤1、步骤2的操作。
减法:
其实减法的操作,就是加法的操作
例如9 - 5,可以看做9 + (-5),9的二进制是 0 0 0 0 1 0 0 1,-5的二进制是 1 1 1 1 1 0 1 1 ,至于-5的二进制为什么会是这个,可以参考我的另一篇博客https://blog.csdn.net/qq_32069155/article/details/92851142。
0 0 0 0 1 0 0 1
1 1 1 1 1 0 1 1
异或--------------------
1 1 1 1 0 0 1 0
,
0 0 0 0 1 0 0 1
1 1 1 1 1 0 1 1
与 --------------------
0 0 0 0 1 0 0 1
,
发现存在进位,则将与运算结果左移一位,得到 0 0 0 1 0 0 1 0,然后将上次异或结果和左移结果再进行异或运算
1 1 1 1 0 0 1 0
0 0 0 1 0 0 1 0
异或--------------------
1 1 1 0 0 0 0 0
,
1 1 1 1 0 0 1 0
0 0 0 1 0 0 1 0
与 --------------------
0 0 0 1 0 0 1 0
,
发现存在进位,则将与运算结果左移一位,得到 0 0 1 0 0 1 0 0,然后将上次异或结果和左移结果再进行异或运算
1 1 1 0 0 0 0 0
0 0 1 0 0 1 0 0
异或--------------------
1 1 0 0 0 1 0 0
,
1 1 1 0 0 0 0 0
0 0 1 0 0 1 0 0
与 --------------------
0 0 1 0 0 0 0 0
,
发现存在进位,则将与运算结果左移一位,得到 0 1 0 0 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算
1 1 0 0 0 1 0 0
0 1 0 0 0 0 0 0
异或--------------------
1 0 0 0 0 1 0 0
,
1 1 0 0 0 1 0 0
0 1 0 0 0 0 0 0
与 --------------------
0 1 0 0 0 0 0 0
,
发现存在进位,则将与运算结果左移一位,得到 1 0 0 0 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算
1 0 0 0 0 1 0 0
1 0 0 0 0 0 0 0
异或--------------------
0 0 0 0 0 1 0 0
,
1 0 0 0 0 1 0 0
1 0 0 0 0 0 0 0
与 --------------------
1 0 0 0 0 0 0 0
,
发现存在进位,则将与运算结果左移一位,得到 0 0 0 0 0 0 0 0,然后将上次异或结果和左移结果再进行异或运算
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
异或--------------------
0 0 0 0 0 1 0 0
,
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
与 --------------------
0 0 0 0 0 0 0 0
,
发现不存在进位,则上次异或结果 0 0 0 0 0 1 0 0就是最终结果,也就是 4。
乘法:
乘法其实跟加法是一样的,只不过是多加了几次而已,这里就偷个懒不多描述了。
除法:
除法其实就是减法,只不过是计算能减多少次而已,这里也偷个懒就不多描述了。
---------------------------------------------------------------------------------------------------------------------------------------
PS:到这你可能还会好奇,为什么异或会跟加法结果一致,我在这里再补充下。
我们要知道,异或运算,是相同位的值不同才为1,值相同则为0。
而且,两个相同位之间出现的可能性,只有4种:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
异或--------------------
0 0 0 0 0 0 0 0
相同位是0 和 0,异或的结果是0,跟直接用加法运算0 + 0的结果也是一致的;
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
异或--------------------
0 0 0 0 0 0 0 1
相同位是0 和 1,异或的结果是1,跟直接用加法运算0 + 1的结果也是一致的;
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
异或--------------------
0 0 0 0 0 0 0 1
相同位是1 和 0,异或的结果是1,跟直接用加法运算1 + 0的结果也是一致的;
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
异或--------------------
0 0 0 0 0 0 0 0
相同位是1 和 1,异或的结果是0,这里跟加法运算1 + 1的结果就不一样了,因为发生了进位。
这四种结果中,有三种结果跟直接加法运算的结果是一样的,最后一种因为存在进位,所以不考虑,上面说过,不参考进位的情况下,异或运算和直接加法运算的结果是一致的。所以,可以肯定的说,不参考进位的情况下,异或运算和直接加法运算的结果一致。
相信到这里,大家应该对异或为什么跟加法结果是一致,有了一定的认识。
本文到此就告一段落了,上述内容,都是我参照https://ke.qq.com/course/320677?taid=2384548663190693这里的视频教程,再进行总结的,如果有什么不对的地方,还请指正!