00:00
我们再来介绍一下skyla当中的未运算符,未运算对于编程语言而言,其实是比较底层的一种计算方式了啊,大家也知道很多语言里边其实都提供了未运算的方式,那像Java,像C啊,都是有这样的一些未运算符的,盖拉里边呢,既然它要跟Java兼容,所以未运算这一部分,它的符号和计算的规则和定义啊,跟Java里边是完全一样的,所以我们这一部分呢,只要做一个复习就可以了,那所谓的未运算其实就是要把两个操作数啊,或者说我们只是考虑某一个操作数,其实就是要把它。表示成计算机底层的二进制编码的形式,然后呢,把这每一位上的0101去做一个操作,啊,那最简单的位运算当然就是暗位语或,还有暗位取反,它可以对应之前我们讲过的逻辑运算符里的逻辑与或非,那这里边的暗谓语跟逻辑语有什么区别呢?呃,前面我们讲过一个简单的要点,就是逻辑语语或可以。
01:10
提前做短路,而这个按位语是不行的,那它们的本质其实是按位语,我们要考虑的是两个数对应位上的那个0101的关系,对吧?啊,那当然他们也有一些共同特点,共同特点就是如果我们把。零,每一位上的零看作逻辑表达式那个布尔类型结果的false,然后把每一位上的一看作处的话,那他们的这个逻辑运算规则其实是可以对应起来的,比如说这里的暗位语,那就是对应,比方说A暗位语B,那么就是A和B展开之后二进制表达每一位上我们考察如果都为一的话,最后结果这一位上就是一,那如果要只要有零,对应的这一位上结果就是零了啊,所以就相当于之前我们那个触和false的一个逻辑与运算一样,我们可以看一看这个具体的例子啊,这个例子是A等于60 B等于13啊,那我们可以把这个二进制表达也写出来,是正数,我们不用考虑呃补码的那种表达啊,直接写出来就可以了,A等于60。
02:23
那写出它的这个表达,大家知道60离着最近的一个二的整次幂是64,六十四十二的六次方一后面六个零,那么如果减一,63就应该是六个一了啊,那就是0011,然后幺幺幺幺六十是在63的基础上还要减三,当然就是把后边的那两个幺都减成011不就是三吗?啊,减掉之后那就是00111100,这就是60的二进制表达,然后呢,B是13啊,这里我们简单起见,把这个A和B都定定义成fat类型。
03:03
只占一个字节,那如果要是int的话,前面我们得补好多零,这个就比较麻烦一点啊,这里我们只考虑BAT,那B等于13的话,呃,大家知道13离得最近的是16,是二的四次方嘛,15的话是四个一啊,就是00001111,那13的话再减掉二,那就应该是0000。1101,这是13,所以接下来我们看A位与B的话,得到的结果,每一位去看全部为一的情况下,结果才是一,只要有零,结果就是零,所以自然我们就看到了。最终得到的就是00001100,这就是13减比13少一,当然就是12了啊,那与之对应的啊,按位。或的计算的话,那其实就是对应位置上如果都是零的时候才是零,只要有一,那就变成一了啊,所以大家看如果是安位货的话,一个括号这里边就是只全是零,对应是零,只要有一就是一,只要有一就是一,哎,这个是零,最后一位还是一,所以看00111101,这比前面60还多了一,所以得到结果其实是61啊,那另外还有一个是按位取反,按位取反这个呢,那当然就只针对一个数有效了啊,那有点类似于之前我们的逻辑非逻辑非的话是处变成false false false变成处,那这里如果是对A按位取反的话,其实就是零变成一,一变成零嘛啊,所以这个时候就60就变成了11000011,对吧?啊,就变成了这样一个数,大家要注意,我们这个BAT类型,它本身是八位的有。
04:58
符号数的二进制补码表达,那所以第一位其实是表示符号位的,本来正60,第一位是零,那现在呢,第一位变成一了,所以它变成了一个负数,那到底是负多少呢?哎,那后面这个补码表示我们再取反加一,取反的话是零啊,就是00111100,这不就是60吗?加100111101,所以是61,最后就是负61啊,这是我们取反之后的这个表达啊,然后这里边还有另外一个比较特殊的位运算符。
05:36
有一些程序代码里边啊,有一些算法里边,这个还是用的比较常见,它比较巧妙,这个就叫做暗卫,抑或这是一个小上间号,它表达的含义是什么呢?是相同位置上的零和幺啊,它做运算的时候是相同为零,相异为幺,什么意思?我们看一下A按位异或B的话,那我们考察。
06:03
上边啊,它对应的每一位啊,如果都是零,那就是零。如果都是一,这两位都是一,它也是零,哎,后面这一位都是零,它也是零,那其他如果要是一个为一,一个为零,它们不相同的情况下,相异才为幺,哎,所以它最后的结果是00110001。那这个数的话,大家看到,呃,这个在第五位上,这是16,第六位上这是32嘛,啊,这是二的五次方和二的四次方,所以32加16 48再加一四十九亦或的结果就是49。啊,这是比较常用的一些未运算相关的一些计算的规则,那另外还有一些就是针对一个操作数做的一个计算,那这个比较特殊一点,它是一个位移运算,那当然就分左位移和右位移了,左位移计算的话,左移计算其实就是。
07:05
朝左的一个箭头啊,写出来的话是两个小于号,看起来像朝左的箭头一样,那么如果是A左移,然后后面跟上二的话,其实就是表示它整体左移两位,那整体左移两位。大家可能会想到,那那左边的如果要有的话,就移出去就没有了,那右边空下的那个补什么呢?当然就补零了,所以大家想到如果右边直接补零。这不就相当于我们之前的一,最末尾的那个一,现在就变成了100,就变成了相当于变成了四吗?哎,所以大家看到啊,最终的结果其实就是把原来的数相当于乘了一个四。左移两位就相当于乘四,为什么是乘四呢?就是二的二次方嘛,所以如果要是左移三位的话,那就相当于乘八,四位的话,那就是乘六,呃,乘16啊,所以这其实就是最终得到的这样一个结果,那同样右移我们用的是大于号,两个大于号看起来像一个向右的箭头一样,那同样它就类似于除以四的,就是如果我们右移两位,就相当于除以四的一个结果。
08:18
那这里比较特殊的是还有一个朝右的三个大于号啊,那这个也是一个右移,但它代表的是无符号右移啊,所以大家看到前面这个呢,它其实是代表有符号的这个状态的,也就是说左移的话,那当然就是符号位不变,那如果要右移的话,右移大家想到往右移动,那是不是左边要补啊,那左边注意也是符号位不变,符号位不变那补的到底是补零还是补一呢?补的是符号位啊,所以这样的话,我们就能保证原先是正的,现在移动之后还是正的,而且它就是就是乘以一个二的整次幂之后的结果,那如果要是原先是负的的话,呃,就是呃,这里如果是右移的话,我们应该是除以一个二的整次幂啊,那如果要是负数的话,右移之后首位还是符号位不变,然后呢,高位补的还都是一,那那当然对应的也是啊,对应的就是一个除以二的整次幂之后的结果了啊,具体我们可以在这个代码里边给大家测试一下,看一看到底是怎么样的啊啊,那后面这个三个大于号,这表示的就是一个不考虑符号,直接右移前面全部。
09:29
补零的这样的一个计算的方式啊,所以接下来我们可以看一看。到底得到的结果是什么样的啊,可以简单的测测试一下,那最后这里我们要测的就是位运算符那前面的。谓语安慰或安慰取反安慰抑或这个我们就不再测试了,大家可以下来之后自己再去做一些,呃,做一些实践啊,这里我们就直接的简单的做一下这样的一个测试,你一个60啊,那里边如果我们直接来啊,它做一个左移三位的一个操作的话,那大家其实能够想到啊,60左移三位应该是什么呢?哎,那。
10:19
60本身我们写出来是00111100嘛,左移三位。其实大家知道现在我们这个定义,它本身是int类型对吧,前面还有很多零补出来的,我们先不去考虑啊,那左移三位的话,那当然就是这里边就都移出去了,对吧?前面的零零就都移到外边了,然后呢,这里的第一个一其实是移到了最外边这里来,然后后边又是一个一,然后后边是1100,后边的三位补零。诶,所以大家看到这样的话,它最终的结果这个是什么呢?Int类型前面都补补齐啊,前面这个应该是00000001,哎,这是这是。
11:04
下面是最后一个字节,这是倒数第二个字节啊,这样得到的结果其实就是。正的480啊,所以就相当于我们这里边是把它做了一个乘乘以八的操作,做一三位嘛,相当于乘以二的三次方啊,那大家可能会觉得有所疑惑,那这个刚才我们考虑的是int类型,如果说里边是一个BAT类型的话,难道说这个数据就溢出了吗?哎,其实不会的,这里边位移之后的结果,它会自动给我们把它转换成一个T类啊,这里边如果大家直接这么去打印的话,你会看到没有问题,得到的结果还是480。哎,这是完全一致的,那同样我们也可以做一个右移的操作,A如果要是向右动两位的话。直接运行,那大家看到当然就相当于除以二的二次方,得到的是15啊,这个是完全没有问题的,然后呃,比方说我们在考察另外一个一个数啊,因为我们说上面的这个都是带着符号的一个左移和右移,所以它就相当于直接乘以一个数或者除以一个数,而且在实际项目当中,大家有时候经常会看到这样的写法,为什么呢?它比直接做这个算术啊,乘以八和除以四的这个计算,它要来的更加的方便,更快,因为大家知道直接按这个位直接去移动吧,计算机底层操作,当然它算的会更快了啊,那呃,这个大家是需要了解的,那我们同样看一下,假如说我定义一个一个B,比方说我这里定义一个short类型啊,那就是只要是整形都没有问题啊B我定一个负数是负的13,这个时候如果说我想要把去做一个,首先做一个。
12:57
左移两位的一个计算得到的应该是什么呢?然后右移两位的一个计算会应该是什么呢?
13:06
在左移哦,这里边我们刚才有的时候删除多删了一个花括号啊,补出来之后我们运行一下。大家看到如果要做对应的一个左移操作的话,它的符号位是负的还是负的。哎,之前我们说这个13本身的这一个二进制表达应该是0000。腰。101应该是这样的一个表达,那现在如果要是呃,这是它的源码啊,那如果要是负13取,就相当于符号位变成一,然后后面要取反加一,那取反的话,其实是111。1111,然后后边是0010,那现在再加一,当然就是0011,这是负13的这个补码的表示,然后现在如果要是左移两位的话,那应该怎么移呢?大家注意是符号位不变啊,当然本来我们定义的是short啊,Short的话应该是两个字节啊,我这里边就直接简略了啊,大家知道这个前面如果就是short前面,因为本来源码前面都是零嘛,那short补出来的话,前面都是幺,这个其实都是都是一致的吧啊,所以我们就把它就删除不看了啊,只看这里就可以了,只看最后一个字节,那就是首位符号位还是幺,那后边后边移怎么移呢?哎,当然就是左移两位,两个一就移没了,然后后边就应该是100,然后幺幺,最后最后补补什么呢?当然还是补零,那大家看一下当前这个补零完。
14:53
那之后这表达的到底是多少呢?按照取反加一,我们找它的源码,当然这个源码就应该是。
15:02
零零取反110011,呃,0011,再加10100。就是这样的一个数啊,那对应的这个数,这个大家也已经知道,这是三十二二的五次方加16,再加上后面这个要加四,那家看当然就是这个加起来48对吧,再加四当然就是52了。其实就是之前负13的。乘以四之后的结果啊,那与之对应,如果要是直接右移的话,右移哎,朝这边移出去,同样还是前面的符号位不变,大家要注意啊,右移的话,那相当于后面这个幺幺就都没了,后面这两位都移出去了,所以我们得到的呢,其实就是11111100,大家注意符号位不变,前面然后补。左边补的时候补什么呢?左边补的话就要补符号位。哎,这样的话就能保证我们前边如果是负数的话,前面还都是幺,哎这样的话就不会改变我们的这个正负的这种情况,而且它的这个大小关系也不会变,取补码之后是一致的,那对应的这个11111100。
16:15
它对应的这个结果又应该是什么呢?这是它的补码,那原码的话当然就是幺符号位,这个是表示它是负的啊,原码的话取反加一取反0000。0011,那不就是000100嘛,所以它其实表示的就是负四对吧?啊,所以得到的就是。这个负13除以二的二的次方除以四之后,哎,大家知道这个为什么得到的是负四而不是负三呢?哎,那这个其实就是因为我们直接移出去之后,那就相当于直接截取当前的整数部分,然后它又是一个补码的表达,那当然其实就相当于是向下取整了,对吧?本来它应该是负三点几,所以这里边我们直接取的是负四啊,它是这样的一个结果。
17:09
呃,当然这个计算跟我们之前大家说的那个整数除法得到结果还是略有不同的,所以大家在实际项目应用的时候,如果不能整除的话,还是要注意一下这个区别的。然后另外大家自然就想到了,那如果我要是做一个无符号右移的话,又是一个什么样的结果呢?比方说无符号右移两位,我们运行一下到的是什么?大家看到这就是一个很大的正数了,为什么呢?因为无符号右移,最终我们左边补的就不是符号位,而补的是零了,哎,那你说之前这个负13最前面都是幺,然后呢,移动之后最前面补了两个零,那当然就变成了一个很大的正数了,哎,所以这个结果大家要考察一下,要能理解到底是怎么样一回事。这就是关于未运算符的一些讲解和说明。
我来说两句