最近这破事贼多,都没有什么时间写写博客,都好久都没有更新博客了!不过平常看jdk源码的时候有很大的感触,就是基础真的很重要,那什么是基础呢?除了java的基本语法之外,最基础的莫过于原码,反码和补码了以及基本的运算了!
又是我是编程半路出家,最开始的时候学过一点这些东西,当时只是感觉,擦!我是写代码的,这些原码什么的有个鸡儿用,有时间看这个还不如多写点代码!但是现在,看了不少源码,回头一看却突然发现自己基础太薄弱了,赶紧补一下基础,装作基础很扎实的样子@_@
1.原码、反码和补码
大家应该都知道,数据在计算机中是以二进制的形式存在的,比如 byte a = 6; byte b = -6
分为两种情况来说,一种是正数,一种是负数;对于正数6来说,原码就是0000 0110,反码和补码也是这个;而对于-6来说,原码就是1000 0110,这是为什么呢?因为最高位(最左边的)是表示符号,0表示正数,1表示负数;
不管是byte,short,int还是其他的数字,最高位都是用来表示符号的,所以-6的原码就是1000 0110,负数的反码就是符号不变,其他的取反,就是1111 1001;负数的补码就是在反码的基础上加1就行了,由于是二进制的,是逢2进1,所以补码就是:1111 1010,;
注意:计算机中的加减运算(计算机中只有加法,可以通过加法表示减法,就是用过补码的形式,看下面栗子)指的是补码之间的运算!而且负数在计算机中是以补码的形式存在并参与运算的,如果要变为十进制,就首先需要变为原码然后才能变为十进制或其他进制的数;
那么0怎么表示呢?我们可以简单看看:0 = 6-6 = 6+(-6)= [0000 0110]补+[1111 1010]补=[0000 0000]补=[0000 0000]原,那么有人要问了,补码1000 0000那又表示多少呢?再看一个简单的-1-127=(-1)
+(-127)= [1000 0001]原+[1111 1111]原 = [1111 1111]补+[1000 0001]补 = [1000 0000]补=[0000 0000]原,两个对比一下,如果都使用原码的话同一个原码[0000 0000]原可以表示两个数0和-128,而用补码的话却可以一个补码对应单独的一个数,很明显,一个补码对应一个数更符合我们的需求!!!
补充一下,对于负数来说,原码和反码之间相互转化,试着理解着记忆:
原码------>反码:符号位不变,其他位取反 ;比如 [1000 0001]原 = [1111 1110]反
原码------>补码:符号位不变,其他位取反,然后+1;比如 [1000 0001]原 = [1111 1111]补
反码------->原码:符号位不变,其他位取反;比如 [1111 1110]反 = [1000 0001]原
反码------->补码:+1 ;比如 [1111 1110]反 = [1111 1111]补
补码------->原码:符号位不变,其他位取反,然后+1;比如 [1111 1111]补 = [1000 0001]原
补码--------->反码:先变为原码,然后变反码;比如 [1111 1111]补 =[1111 1110]反
这些都是基本的东西,只要记住在计算机中运算的话,都是以补码的形式,而且这里就会涉及到一个过程,画一个简单的图,计算机中运算都是用补码来进行的;而中间的转化过程计算机可以十分迅速的转化,这个就不用我们操心;下面我们就看看那个运算到底包括哪些运算。。。
2.基本的运算
说起现实中的运算,无非就是四则运算,加减乘除,而对应于计算机中也有加减乘除,加减已经在上面说了,可以用补码的加法来实现加减,但是乘除呢?在这里我们就说说最简单的乘除法啊,乘以2和除以2这种,如果是乘除其他数还是比较复杂的,暂时我也没有什么兴趣研究,有兴趣的小伙伴可以查查计算机中乘除法的实现,你会沉迷其中不可自拔!
以byte类型来举例,byte类型最高位是符号位,所以范围是在1111 1111到01111 1111之间,变成十进制也就是-127到127,加上0000 0000这个原码对应两个数0和-128,所以整个的范围就是-128到127;
乘除也是分为两大块,正数和负数;
2.1 正数乘2运算(左移用<<表示)
我们看看一个简单的数(这里我正数也写一下补码):byte a = 5; 5的原码为:[0000 0101]原=[0000 0101]补 ;乘以2就等于10,原码为[0000 1010]原=[0000 1010]补
看看这两个补码有什么关系?就是将5的补码最右边添加一个0,最左边去掉一个0!最好是将5的补码看作一个整体,这个整体向左移动一位,左边超过的位数直接去掉,右边空的位置添0