原码,反码,补码间的关系
原码: 就是二进制定点表示法,最高位为符号位, 最高位是“0”,表示该数为正数,最高位是“1”,表示该数为负数。
反码: 正数的反码与其原码相同,负数的反码是对其原码除开符号位以外的数值位逐个位取反。
补码: 正数的补码和其原码相同,负数的补码是在其反码的末尾进行加1;
因为所有参与计算的数据都是二进制的补码,所以我们要得到计算过程就得先得到这些数据对应的补码。
正数的 原码,反码 ,补码都是一样的。
负数的 反码等于 符号位 除外的其他位取反,补码等于反码最后一位加一,符号位不变;
如下:
eg: byte类型数据,一个字节等于 8 个bits
+5
符号位 数值位
原码 0 0000101
反码 0 0000101
补码 0 0000101
-7
符号位 数值位
原码 1 0000111
反码 1 1111000
补码 1 1111001
+5 + -7 byte 类型 进行计算是会自动提升为 int 类型,就得用 32位 ,4个字节来表示了。
如下
符号位 数值位
负数
原码: 1 0000000 00000000 00000000 00000111
反码: 1 1111111 11111111 11111111 11111000 符号位不变,其他位取反
补码: 1 1111111 11111111 11111111 11111001 反码末尾加1
正数 0 0000000 00000000 00000000 00000101 原,反,补一个样。
结果的补码: 1 1111111 11111111 11111111 11111110 从最右边开始两数的 0和1,逢2进1;
再通过这个补码就可以得到结果的原码,也就可以得到十进制的结果的数值,如下:
结果的反码: 1 1111111 11111111 11111111 11111101 补码末尾减去1
结果的原码: 1 0000000 00000000 00000000 00000010 符号位不变,其他位取反 结果就是 -2了
+127 + -125 byte 类型 进行计算是会自动提升为 int 类型,就得用 32位 ,4个字节来表示了。
如下
符号位 数值位
负数
原码: 1 0000000 00000000 00000000 01111101
反码: 1 1111111 11111111 11111111 10000010 符号位不变,其他位取反
补码: 1 1111111 11111111 11111111 10000011 反码末尾加1
正数 : 0 0000000 00000000 00000000 01111111 原,反,补一个样。
结果的补码:(1) 0 0000000 00000000 00000000 00000010 从最右边开始两数的 0和1 ,逢2进1;超出的部分去掉,得到了 2
因为结果的最高位是0 ,所以是个正数,原码,反码,补码都一样,所以结果就是2了。
** 位运算的符号有 & , I ,^ , ~ , >> , << , >>> **
3的二进制 : 00000000 00000000 00000000 00000011
4的二进制 : 00000000 00000000 00000000 00000100
(这里的两个数都是正数,所以原码,反码,补码都是一样的,但是记住在计算的时候一定是他的补码参与运算)
& 位 与 运算 (与逻辑运算符类似,相同都为1则是1,有0或者都是0结果是0,是不是和 true & false 类似呢)
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000100
-----------------------------------------------------
00000000 00000000 00000000 00000000 3 & 4 == 0(可以 验证结果 (3 & 4);)
| 位 或 运算 (与逻辑运算符类似,有1则是1,都是0结果才是0,这个是不是也和 true & false 类似呢)
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000100
-----------------------------------------------------
00000000 00000000 00000000 00000111 3 | 4 == 7 (可以 验证结果 (3 | 4);)
^ 位 异或 运算 (与逻辑运算符类似,相同则是0,不同则是1,这个是不是也和 逻辑运算符的判断类似呢,相同则是false,不同则是true)
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000100
-----------------------------------------------------
00000000 00000000 00000000 00000111 3 I 4 == 7 (可以 验证结果 (3 ^ 4);)
eg:^ 运算的特点是,每个数被另一个数 ^ 两次其值不改变,
int a = 10;
int b = 20;
(a^b^b);
(b^a^a);
~ 按位取反运算符 3
00000000 00000000 00000000 00000011 补码
(取反)11111111 11111111 11111111 11111100 补码
这里的最高位是1 ,没错最高位是 1 的话是一个负数。
所以我们先得到他的反码,也就是补码末尾减去 1;
11111111 11111111 11111111 11111011 反码
10000000 00000000 00000000 00000100 原码
所以结果为-4 ,验证结果((~3);)
~ 按位取反运算符 -4
10000000 00000000 00000000 00000100 原码
11111111 11111111 11111111 11111011 反码
11111111 11111111 11111111 11111100 补码
用补码来进行 按位取反的运算
00000000 00000000 00000000 00000011 补码
最高位是0,所以是个正数,原码,反码,补码相同,所以原码如下:
00000000 00000000 00000000 00000011 原码
所以结果为 3 ,验证结果((~(-4));)
<< : 左移,左边最高位不变,右边补零。
>>: 右移, 左边最高位是 0,左边补0,最高位是1,左边补 1;
>>>: 无符号右移,无论最高位是1还是0,左边补0;
eg : -24 <<< 2
原码: 10000000 00000000 00000000 00011000 (取反,符号位不变,得到反码)
反码: 11111111 11111111 11111111 11100111 (末尾加1,得到补码)
补码: 11111111 11111111 11111111 11101000
左移2位: (11)11111111 11111111 11111111 10100000 补码 (最高位是1,末尾减去1,得到反码)
反码:11111111 11111111 11111111 10011111 反码 (按位取反,最高位的符号位除外,得到原码)
原码:10000000 00000000 00000000 01100000 原码 结果等于 -96
验证结果:(-24 << 2); -24*2^2
位移计算相当于:
左移 == 该数 *2^位移次方
右移 == 该数 / 2^位移次方 (结果除不尽时,对结果 ceil)
进制之间的转换:
十进制的128, 用二进制来表示是: 10000000 (一个字节用 8 bits 表示) 根据二进制的公式来计算过程如下所示
byte b = 128 ;二进制数据以0b 开头 即: 0b10000000
字节表示: 10000000 == 将二进制计算成十进制数据 128= 127+0+0+0+0+0+0+0*20;
那如果用八进制来表示 128 会是什么样的呢?把二进制的源码,三位一组排列,位数不够的在右边补0,然后分别根据二进制计算十进制
的方法计算出来每一个八进制位数上数值,再跟所在的八进制 数 位数-1 次幂 相乘得到每一个8进制位数上的结果再相加得到最后结果。
八进制是三个位表示一组 ,如下: 010 000 000 得到公式 : 121*82+020*81+020*80=264=128 就得到了八进制对应的十进制数据 以0开头 0200;(28^(3-1))
再转换成 十六进制我们该怎么表示呢? 原理与8进制大同小异,可以参考8进制的算法。
十六进制是 4个位表示一组,如下: 1000 0000 得到公式: 123*161+020*160 =816=128 就得到了十六进制对应的十进制数据 以0x开头 0x60(6161+0*160)
这些都是二级制快速转成其他进制数的方法
这里对这种方法做一个解释。
系数:每一个位上的数据表示该位的系数;
基数:X进制的基数就是X;
权:也相当于几次方(幂) ,从右往左依次编号,从0开始。
每一个数就等于 每一个位数 * 基数 * 权
就比如十进制的 1234 == 110(4-1)+2*102+3101+4*100