原码,反码,补码
原码是十进制整数的二进制表示形式,最左边的一位是符号位,0为正,1为负。当我们使用原码进行数的计算时,会发现如果数为正数,可以正常计算,如果为负数,就会出现问题。
例如:
10000000是-0的原码,现在要计算0+1,1的原码为00000001,相加结果为10000001,转换为十进制是-1,而不是1,同理,我们使用-1的原码10000001计算一下-1-1,就会是10000000,是0的原码,不是-2,由此可知,我们在用原码计算与负数有关的计算时,会出现问题。
因此,反码出现了。反码的计算规则是:正数的反码与原码相同,负数的反码是符号位不变,其余位0变1,1变0。使用反码之后,就可以计算负数有关的运算了
例如:
计算-57+1,-57的原码为1100 0111,反码为1011 1000,1的反码与原码相同,为0000 0001,将二者相加,结果为1011 1001,我们再将反码转为原码,得到1100 0110,正好是-56的原码,所以,反码一定程度上解决了负数计算的问题。
但是,如果在计算中出现跨0的情况,如-1+2=1,又会出现新的问题,这也是反码的弊端
如:-1 的原码为1000 0001,反码为1111 1110 2的原码反码相同 为0000 0010,二者相加的结果为0000 0000(实际上是再向前进一位 0001 0000 0000但这里考虑的是一字节的情况,所以只看8位。)由于符号位是0,所以原码与反码相同,所以相加结果是0 不是1。造成这个问题的原因是,原码中,0有两种表示方式,即0000 0000和1000 0000,对应反码中0也有两种表示方式,即0111 1111和0000 0000,因此,在涉及到跨0的运算时,结果往往会比实际的要少1.为了解决这个问题,大佬们提出了补码。
在补码中,正数依旧是与其原码相同,而负数的补码可以理解为将其反码向下错了一位
十进制数 原码 反码 补码
0 00000000(+0) 00000000(+0) 00000000
10000000(-0) 11111111(-0) 00000000
-1 10000001 11111110 11111111
-2 10000010 11111101 11111110
-3 10000011 11111100 11111101
-4 10000100 11111011 11111100
-5 10000101 11111010 11111011
如表格所示,将负数的反码向下错一位,也就是在反码的基础上加一计算得到的,变成补码,就解决了0在反码有两种表现形式的问题,所以在涉及到跨0的计算时,就可以正常运算。
此外,由于补码的计算将反码向下错了一位,所以一定会多出一位,也就是1000 0000,他代表的数字是-128,-128没有原码和反码。所以一字节的取值范围,也规定为-128~127。
在了解原码反码补码后,就可以解释一些运算。
1.隐式转换
在java中 byte short int long所占用的字节数分别为1 2 4 8,再进行隐式转换时,逻辑是在前面补够对应的0。
比如byte a=10;int b=a; byte类型的10的补码为0000 1010。当执行第二句代码时,系统会将他隐式转换为int类型 此时的补码就变成了0000 0000 0000 0000 0000 0000 0000 1010。
2.强制转换
强制转换中的大转小,逻辑是去掉相应的位数,小转大的逻辑同上
如int a=200;byte b=(byte)a;a开始为int型,补码为0000 0000 0000 0000 0000 0000 1100 1000,byte只占一个字节,所以只保留最后八位,即1100 1000,需要注意的是,第一位是符号位,所以强制转换的结果应为-56
3.逻辑与&(1为true 0为false)
在进行逻辑与运算时,两个数的补码对应位数上的数字若相同,则结果是1 反之是0
4.逻辑或 |
进行逻辑或运算时,有1结果就是1,反之就是0
5.右移>>,左移<<,无符号右移>>>
左移时,低位补0,左移几位,低位补几个0,相当于原十进制数字乘几个2
左移时,高位补0或1,右移几位,高位的数字位补几个0,符号位补与原数字相同的符号,相当于原十进制数字除以几个2
无符号右移与右移的区别在于,符号位无论原数字是正是负,都补0

浙公网安备 33010602011771号