补码
Java内部以二进制进行数值计算
补码规则
- 在计算机系统中,数值一律用二进制补码存储
- 二进制最高位是符号位
- 正数的值是其本身,负数的值是最高位(符号位)不便,其他位逐位取反,再加1
(1101)2
0010 逐位取反
0011 加1
1101(2) = -3
- 两数相加,若最高位符号位有进位,则进位被舍弃
为什么使用补码
- 可以将符号位和其他位统一处理
- 最高位不再标识数值,而是作为符号位,正好将数值折半
- 减法可当加法处理
- 就是让计算机能够只用一种电路逻辑表示加法和减法
补码运算的特征
- 计算机中正数和负数的关系是取反加一
- 补码运算是封闭的,运算结果保留在补码范围之内,超范围就溢出
- 4位二进制补码最多能表示2^4个数,数的范围是-8~7
- 8位二进制补码最多能表示2^8个数,数的范围是-128~127
- 16位二进制补码最多能表示2^16个数,数的范围是-32768~32767
- 32位二进制补码最多能表示2^32个数,数的范围是-2^31~2^31-1
补码运算的原理
正数+负数=模
模:某种类型数据的总数
负数=模-正数
引用[阮一峰]
2的补码的本质
在回答2的补码为什么能正确实现加法运算之前,我们先看看它的本质,也就是那两个步骤的转换方法是怎么来的。
要将正数转成对应的负数,其实只要用0减去这个数就可以了。比如,-8其实就是0-8。
已知8的二进制是00001000,-8就可以用下面的式子求出:
00000000
-00001000
---------
因为00000000(被减数)小于0000100(减数),所以不够减。请回忆一下小学算术,如果被减数的某一位小于减数,我们怎么办?很简单,问上一位借1就可以了。
所以,0000000也问上一位借了1,也就是说,被减数其实是100000000,算式也就改写成:
100000000
-00001000
---------
11111000
进一步观察,可以发现100000000 = 11111111 + 1,所以上面的式子可以拆成两个:
11111111
-00001000
---------
11110111
+00000001
---------
11111000
2的补码的两个转换步骤就是这么来的。
用补码,意味着CPU在加减运算时可以不考虑正负号,只要考虑是否有溢出即可(实际上大部分时候连溢出都不必考虑),因为补码实际上就是带补位的二进码,你可以这样理解:
-5 就是 0 减去 5 得到的值,当然,0 是带补位的(1)0 - 5,对应的二进制就是(按8bit字节)(1)00000000 - 00001001 = …….,实际上,不补那个1(不考虑溢出)00000000 - 00001001得到的结果是一样的!
实际上,补码的本质就像一个圈,在圈上设一个点,表示0;顺时针表示正;逆时针表示负;顺着时针走,走到最远一点,是最大正值,继续走,阳极生阴物极必反,就到负最大,在继续走,仍然可以保持“顺着时针走表示加法的意思”。