byte b = (byte)322;
System.out.println(b);//66
传统计算机底层只能识别二进制,存储和读取数据时都要使用二进制数表示。
强制把int类型转成byte类型,int类型是4个字节32位,用这32位表示322,即00000000 00000000 00000001 01000010
,现在要转成只能装下一个字节的byte,只能把前面24位截掉成01000010
,
表示的数即66;
以下只以一个字节为例,多了就截掉
表示正负数
采用最高位是符号位的方法来区分正负数,正数的符号位为0、负数的符号位为1。
byte b = (byte)130;//b = -126
00000000 00000000 00000000 10000010
符号位是0,表示正的130;把前面截掉成10000010
,最高位是符号位1,即负数,所以是-2?(二进制的10代表十进制的2)
其实计算机存储数据时,一律储存二进制的补码形式
对于正整数来说,原码、反码、补码相同
对于负数来说
byte b = -1;
二进制原码:10000001
反码:符号位不变,其它位取反,11111110
补码:反码+1,11111111
可以发现,一个负数的反码+这个负数的相反数(即正数)的原码=11111111
负数的反码可以用11111111-正数的原码表示
如-1的反码=1111111-00000001=11111110
补码再转回原码?要反推吗?
补码:11111111
反码:补码-1,11111110
原码:10000001
不用反推,把补码当成原码,正推即可得到10000001
原码:11111111
反码:10000000
补码:10000001
10000010
其实是补码,-> 11111101
-> 11111110
,1111110
转为10进制为126,加上符号1
,表示-126
可能有人不知道1111111-00000001=11111110
补充一下减法规则:0-0=0,10-1=1(向高位借位) 1-0=1,1-1=0
2-1=1
00000100
- 00000011
= 00000001
37-27=10
00100101
- 00011011
= 00001010
为什么计算机要以补码形式存储
计算机只会算二进制的加法,不会减法,0+1=1,0+0=0,1+1=10(进位,别问为什么不是2了)
以1个字节为例
2+3=5
00000010
+00000011
=00000101,即5
42+99=141
00101010
+01100011
=10001101,即141
14+7=21
00001110
+00000111
=00010101
说明一下,十位1+1=10,把0写下边,1进位
百位1+1还要加进位的1,即11,把1写下边,1进位
千位1+0加进位的1,即10,把0写下边,1进位
那么1-1怎么算,只能转成1+(-1)
00000001
+10000001
=10000010,-2
1-1=-2看来行不通,使用原码根本不适合减法运算
使用反码做减法运算
还是1-1,正数的反码不变,负数的反码是除了符号位不变,其它位取反10000001
->11111110
两个数转换为反码,后相加得到的反码再转成原码
1+(-1)=0
00000001
+11111110
=11111111
11111111->10000000即-0即0
2+(-1)=1
00000010
+ 11111110
=100000000,即00000000,0错了
解决了1-1=0的问题
但是以反码存储,+0是00000000,-0是11111111,同样的一个0,以反码储存却有两种形式
使用补码做减法运算
1的补码是00000001
,-1的补码是11111111
1+(-1)=0
00000001
+ 11111111
=100000000,最高存储8位,舍去1,剩下的8个0是非负数,补码与原码一致,为0
2+(-1)=1
00000010
+ 11111111
=100000001,舍去最高位1,即00000001,1
54+(-53)=1
-53的原码10110101->11001010->11001011
00110110
+ 11001011
=100000001,...1
24+(-4)=20
-4的原码10000100->11111011->11111100
00011000
+ 11111100
=100010100,截掉1得00010100,即20
-127+(-1)=-128
10000001
+ 11111111
=110000000->10000000(谁的补码是10000000,好像目前还没有(别说是0))
0的补码是00000000
,-0的补码(原码10000000->反码11111111->补码100000000),超出8位,截去1,剩下00000000
,存储时都是00000000
解决了存储0时不一致的问题
使用补码存储的目的是为了解决减法运算问题
怎么用一个字节表示-128
byte使用1个字节表示了-128~127范围的整数,-127和127还好表示
一律存储补码形式,非负数的补码、反码、原码都一致
0到127
0 : 00000000
1 : 00000001
2 : 00000010
....
126 : 01111110
127 : 01111111
128 : 10000000错 最高位是符号位别占用
-0到-127
-0 : 10000000 -> 11111111 -> 100000000 -> 00000000
-1 : 10000001 -> 11111110 -> 11111111
-2 : 10000010 -> 11111101 -> 11111110
-3 : 10000011 -> 11111100 -> 11111101
-4 : 10000100 -> 11111011 -> 11111100
-5 : 10000101 -> 11111010 -> 11111011
-6 : 10000110 -> 11111001 -> 11111010
-7 : 10000111 -> 11111000 -> 11111001
...
-126: 11111110 -> 10000001 -> 10000010
-127: 11111111 -> 10000000 -> 10000001
如果以原码的形式存储数据,1个字节最多表示-127到127的整数,128是9位存储不了
-128 : 110000000 -> 101111111 -> 110000000 -> 10000000
但是使用补码的形式存储,发现还有10000000没用上,使用10000000表示-128没有问题
byte num1 = -127;
byte num2 = -2;
System.out.println((byte)(num1+num2));//127
-127+(-2)为什么是127
10000001
+ 11111110
=101111111->强转成byte只有8位,截去后的结果01111111->127
-127+(-7)为什么是122
10000001
+ 11111001
=101111010->01111010->122
上面得到的结果是正数,所以补码与原码相同,不需要取反+1
-3+(-4)=-7
11111101
+ 11111100
= 111111001->100000110->100000111->-7
可以看到负数转为补码做减法运算很方便,只是超出了[-128~127]范围后会有精度损失
int num1 = 2147483647;
int num2 = 7;
System.out.println(num1+num2);//-2147483642
2147483647的补码原码相同如下
01111111 11111111 11111111 11111111
+ 00000000 00000000 00000000 00000111
= 10000000 00000000 00000000 00000110 结果是负数的补码与原码不一致
10000000 00000000 00000000 00000110
11111111 11111111 11111111 11111001
11111111 11111111 11111111 11111010//最前面的是符号位,即-2147483642
使用工具验证时记得把空格去掉
补码为什么等于反码+1
两个相反数相加要等于0,如1+(-1)=0,以原码储存负数做不到,需要换个编码形式存储负数,暂且设这个码已经存在,为*码
11111111
+ 00000001
=100000000->00000000->即0
设一个正数,则它的相反数暂时称负数,正数+(负数)=0,同时负数以*码存储
正数的原码+(负数的*码)=00000000=11111111+00000001
(11111111-正数的原码)+00000001=(负数的*码)
由
得
负数的反码+00000001=负数的*码
负数的*码 = 负数的反码+1
现在称*码为补码,补码=反码+1
头铁的可以算补码 = 0 - 正数的原码
我还在网上找了个比较简单的补码算减法 补码是减法