前言
首先数据在计算机中存储的是补码,输出的时候是将补码转化成原码输出。在计算机底层运算的时候,都是使用补码进行运算。以下说明均以32位状态为例。
一、原码、反码、补码相互转化
说点题外话,为什么负数的存储如此之麻烦,是因为计算机在底层存储数据的时候为了保证负数能和正数一样直接进行加法操作,只用定制一套规则就可以进行正数+负数或者负数+负数操作。为了保证逻辑不跳转。
负数
1.原码转反码:符号位不变,其他位按位取反
-1的原码: 10000000 00000000 00000000 00000001
-1的反码:11111111 11111111 11111111 11111110
2.反码转补码:在反码的基础上加1
-1的补码:11111111 11111111 11111111 11111111
因此-1在计算机中存储的是32个1
正数
正数在计算机中的原反补相同,不需要向负数一样相互转化
2的原码:00000000 00000000 00000000 00000010
反码和补码和原码都相同
因此2在计算机中存储的是:00000000 00000000 00000000 00000010
零
0的原码:00000000 00000000 00000000 00000000
0在原码变反码的时候,符号位也要取反:11111111 11111111 11111111 11111111
反码变补码:+1:00000000 00000000 00000000 00000000
二、关于取反~
最近新学了一个知识:对a取反再+1操作后可以得到a的相反数(此处的a可以是正数,也可以是负数)
因为计算机在底层运算的时候都是补码运算,所以以下举例均为补码。
当a为正数:a = 5
原反补码:00000000 00000000 00000000 00000101
接下俩对a取反:注意此处所说取反与原反补的取反不同,符号位也要取反!!!
~a : 11111111 11111111 11111111 11111010
再+1:11111111 11111111 11111111 11111011 (1)
注意:此时加1后的结果在内存中存的是补码,最高位是1,代表是负数,负数的原反补不同。要想输出该数表达的是多少,需要将其变成原码。
(1)号式子变反码:减1操作:11111111 11111111 11111111 11111010
再执行符号位不变,其他位按位取反变原码:10000000 00000000 00000000 00000101
此时可以看出,最高位是1,表示负数,计算成十进制就是:-5
当a为负数:a = -7
因为是补码参与运算,所以这里直接给出-7的补码:11111111 11111111 11111111 11111001
~a : 再次注意!!!这里取反包括符号位:00000000 00000000 00000000 00000110
+1:00000000 00000000 00000000 00000111
加1后的结果在内存中存的是补码,最高位是0,可以看出该数是正数,而正数的原反补相同,所以+1后的结果也可以是原码,所以原码直接转成十进制就是:7
当a为0:
补码:00000000 00000000 00000000 00000000
取反:11111111 11111111 11111111 11111111(取反包括符号位)
+1:00000000 00000000 00000000 00000000
整型中最小的负数取反+1:
整型在JAVA中都是有符号的,范围从-(2^31)~2^31-1,可以看出正数的值比负数的值少1,所以正数的相反数都有对应的负数表示,但最小的负数却没有对应的正数表示。
最小的负数的补码:10000000 00000000 00000000 00000000
取反:01111111 11111111 11111111 11111111(取反包括符号位)
+1:10000000 00000000 00000000 00000000
+1后的结果在内存中也是补码,可以看到和原来没有取反加1前的补码相同,因此整型中最小的负数取反还是它本身。
因为除了符号位之外的数都是0,所以可以将符号位的1看成是负数,然后符号位的1参与运算,即为 -(2^31)
三、总结
正数在内存中存储(补码)的最高位是0
负数按照原反补转化(符号位不变),可以得出在内存中存储(补码)的最高位是1