用二进制表示数字,需要考虑以下几个问题
- 表示范围,有正数,负数和 0
- 运算方便
- 0 只有一种表示,如果两种表示需要在做底层运算时候进行判断,增减性能损失。
原码
如果用二进制表示正数和负数,可以想到用最高为来代表符号位,符号位不参与数值运算
这就是原码,最直观的表示,0 代表正数,1 代表负数。
以 8bit 的 byte 为例,以下均为 byte
0000 0001
为 1,1000 0001
为-1
但是 0000 0000
和 1000 0000
均表示 0
运算也不方便,-1+3 和 1+(-3)
1000 0001
+0000 0011
=1000 0100
= -4?
0000 0001
+1000 0011
=1000 0100
= 4?
用进位算法肯定是不行的。只能计算绝对值之差,前面加上绝对值大的数的符号。
如果用原码表示,那范围是-127-127.
所以原码满足了问题 1,但是不满足问题 2 和 3
补码
原码的最高为没有参与数值计算,导致 0 有两种表示方法
如果让最高为参与数值计算呢?这样 0 就只有 0000 0000
一种表示方法
同时因为最高为参与了数值运算,所以在进位加法中最高位和其他位的作用一样,都可以参与与其他数对应位的运算中。
比如-1+3 和 1+(-3)
1111 1111
+0000 0011
=0000 0010
= 2
最高位的进位扔掉,结果为 2,正确。
1111 1111
+0000 0011
=0000 0010
= 2
所以补码满足了问题 1,3,但是问题 2 还有一个减法需要考虑,而我们可以把减法换成加法
比如 1-3 转换成 1+(-3),问题是 3 的原码怎么转换成-3 的补码
计算补码的方法
public static void main(String[] args) {
int a = -10;
// 0x8000_0000 = 1000 0000 0000 0000 0000 0000 0000 0000
for (int i = 0; i < 32; i++) {
int t = (a & (0x8000_0000 >>> i)) >>> (31- i);
System.out.print(t);
}
}
反码
正常操作都是先说反码再说补码,这里最后说反码是作为原码转换补码的桥梁。
反码的作用是从原码计算出补码 -1 的原码 1000 0001
计算出补码 1111 11111
,除最高位取反 +1 就可以。
除最高位取反就是原码的定义。不过我觉得没什么用。
机器数
机器数好像是以补码表示形式存储的,用补码的好处是方便运算,而用原码的好处就方便展示。
可能考虑到程序中运算的时候远远多于展示需要的时间,所以用补码存储吧。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于