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时不一致的问题
使用补码存储的目的是为了解决减法运算问题
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 使用工具验证时记得把空格去掉
两个相反数相加要等于0,如1+(-1)=0,以原码储存负数做不到,需要换个编码形式存储负数,暂且设这个码已经存在,为*码
11111111 + 00000001 =100000000->00000000->即0
设一个正数,则它的相反数暂时称负数,正数+(负数)=0,同时负数以*码存储
正数的原码+(负数的*码)=00000000=11111111+00000001 (11111111-正数的原码)+00000001=(负数的*码)
由
得
负数的反码+00000001=负数的*码 负数的*码 = 负数的反码+1
现在称*码为补码,补码=反码+1
头铁的可以算补码 = 0 - 正数的原码
我还在网上找了个比较简单的补码算减法 补码是减法