前言
由于HashMap内部机制较为复杂,本章先介绍一些基础逻辑以及基本概念,为下章的源码分析做铺垫。
本文内容
- 机器数,真值,原码, 反码, 补码
- 各个进制之间的相互计算
- 位运算符
一、机器数和真值
首先要介绍机器数和真值的概念
Int类型的变量占4字节(byte),32位(32bit),这里缩减了32位的长度为16位,方便阅读
1.机器数
-
数字在计算机之中的表示即为机器数,机器数的最高位为符号位,正数为1,负数为0。
例子如下:
| 10进制值 | 机器数 |
|---|---|
| 10 | 0000 0000 0000 1010 |
| -10 | 1000 0000 0000 1010 |
2.真值
-
因为机器数的最高位为符号位,不能等于真正的数值,所以真值的最高位为符号位,正数为+,负数为-
例子如下:
| 10进制值 | 机器数 | 真值 |
|---|---|---|
| 10 | 0000 0000 0000 1010 | +000 0000 0000 1010 |
| -10 | 1000 0000 0000 1010 | -000 0000 0000 1010 |
二、原码,反码,补码
计算机要使用一定的编码方式进行存储,原码反码, 补码,是机器存储一个具体数字的编码方式。
1.原码
-
原码的最高位为符号位,正数为1,负数为0。加上真值的绝对值。所以8位的二进制数的取值范围是,[1111 1111 1111 1111 , 0111 1111 1111 1111],即[-32767, 32767]
例子如下:
| 10进制值 | 原码 | 真值 |
|---|---|---|
| 10 | 0000 0000 0000 1010 | +000 0000 0000 1010 |
| -10 | 1000 0000 0000 1010 | -000 0000 0000 1010 |
2.反码
反码规则如下:
-
正数的反码是原码本身
-
负数的反码符号位不变,其余各位取反
例子如下:
| 10进制值 | 原码 | 反码 |
|---|---|---|
| 10 | 0000 0000 0000 1010 | 0000 0000 0000 1010 |
| -10 | 1000 0000 0000 1010 | 1111 1111 1111 0101 |
3.补码
补码规则如下:
-
正数的补码是反码本身
-
负数的补码是反码的基础上+1
例子如下:
| 10进制值 | 原码 | 反码 | 补码 |
|---|---|---|---|
| 10 | 0000 0000 0000 1010 | 0000 0000 0000 1010 | 0000 0000 0000 1010 |
| -10 | 1000 0000 0000 1010 | 1111 1111 1111 0101 | 1111 1111 1111 0110 |
4.原码,反码,补码为何存在
-
如果要计算机通过辨别符号位会使基础电路设计变得十分复杂,所以运用数学原理,减去一个正数相当于加上一个负数,所以计算机只通过加法就可实现加减。如果用原码进行计算显然是错的,我们如果用反码计算会得到如下结果。
十进制计算:10+10=20
二进制反码计算:0000 0000 0000 1010 + 1111 1111 1111 0101 = 1111 1111 1111 1111
1111 1111 1111 1111 的原码为 1000 0000 0000 0000 = -0
虽然通过反码计算,结果的真值是正确的,但是0带符号位是没有意义的,我们在尝试用补码计算,会得到如下结果。
十进制计算:10+10=20
二进制补码计算:0000 0000 0000 1010 + 1111 1111 1111 0110 = 0000 0000 0000 0000
0000 0000 0000 0000 的原码为 0000 0000 0000 0000 = 0
这样就可以解决-0的问题,并且1000 0000 0000 0000表示-32768。另外-1-32767=-32768,在补码运算中为1000 0000 0000 0000就是-32768, 但是注意因为实际上是使用以前的-0的补码来表示-32768, 所以-32768并没有原码和反码表示.(对-32768的补码表示1000 0000 0000 0000算出来的原码是0000 0000 000 0000, 这是不正确的)
三、进制计算
1.二进制 → 十进制
二进制数从低位到高位(即从右往左)计算,第0位的权值是2的0次方,第1位的权值是2的1次方,第2位的权值是2的2次方,依次递增下去,把最后的结果相加的值就是十进制的值了。
例:将二进制的(101011)转换为十进制的步骤如下:
第0位 1 x 2^0 = 1
第1位 1 x 2^1 = 2
第2位 0 x 2^2 = 0
第3位 1 x 2^3 = 8
第4位 0 x 2^4 = 0
第5位 1 x 2^5 = 32
1+2+0+8+0+32=43,即(101011)=(43)
2.十进制→ 二进制
除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数读起,一直到最前面的一个余数。
例:将十进制的(43)转换为二进制的步骤如下:
将商43除以2,商21余数为1
将商21除以2,商10余数为1
将商10除以2,商5余数为0
将商5除以2,商2余数为1
将商2除以2,商1余数为0
将商1除以2,商0余数为1
因为最后一位是经过多次除以2才得到的,因此它是最高位,读数字从最后的余数向前读,101011,即(43)=(101011)
3.扩展
1.包含小数的进制换算
(ABC.8C)H=10x16^2+11x16^1+12x16^0+8x16^-1+12x16^-2
=2560+176+12+0.5+0.046875
=(2748.546875)D
2. 负次幂的计算:
2^-5=2^(0-5)=2^0/2^5=1/2^5
同底数幂相除,底数不变,指数相减,反过来
四、位运算符
1.<<左移
低位补0,高位被遗弃
- 正数:r = 20 << 2
20的二进制补码:0001 0100
向左移动两位后:0101 0000
结果:r = 80
- 负数:r = -20 << 2
-20 的二进制原码 :1001 0100
-20 的二进制反码 :1110 1011
-20 的二进制补码 :1110 1100
左移两位后的补码:1011 0000
反码:1010 1111
原码:1101 0000
结果:r = -80
2.>>右移
该数为正,则高位补0,若为负数,则高位补1,低位被遗弃
- 正数:r = 20 >> 2
20的二进制补码:0001 0100
向右移动两位后:0000 0101
结果:r = 5
- 负数:r = -20 >> 2
-20 的二进制原码 :1001 0100
-20 的二进制反码 :1110 1011
-20 的二进制补码 :1110 1100
右移两位后的补码:1111 1011
反码:1111 1010
原码:1000 0101
结果:r = -5
3.>>>逻辑右移(无符号右移)
高位补0(无视正负),低位被遗弃
- 正数: r = 20 >>> 2
的结果与 r = 20 >> 2 相同;
-
负数: r = -20 >>> 2
注:以下数据类型默认为Int32位
-20:源码:1000 0000 0000 0000 0000 0000 0001 0100
反码:1111 1111 1111 1111 1111 1111 1110 1011
补码:1111 1111 1111 1111 1111 1111 1110 1100
右移:0011 1111 1111 1111 1111 1111 1111 1011
结果:r = 1073741819
当Int类型的数据进行左移的时候,当左移的位数大于等于32位的时候,位数会先求余数,然后再进行左移,右移同理
4.&(与操作符)
同为1结果为1,否则为0
- 0 & 0 = 0
- 0 & 1 = 0
- 1 & 0 = 0
- 1 & 1 =1
5.|(或操作方)
1出现为1,否则为0
- 0 | 0 = 0
- 0 | 1 = 1
- 1 | 0 = 1
- 1 | 1 = 1
6.^(异或操作符)
不同为1,相同为0
- 0 ^ 0 = 0
- 0 ^ 1 = 1
- 1 ^ 0 = 1
- 1 ^ 1 = 0
7.~(取反操作符)
0变1,1变0
总结
本文讲述的都是计算机基础,为了下章的扰乱函数解析做出铺垫,也可当作字典,当知识遗忘时可供查阅。