byte: 8位[-128~127]
short: 16位[-32768~32767]
int: 32位[....很大]
计算机只做加法。
计算机进行运算时,将符号位也当做数值位参与运算。
二进制进行加法如果溢出,溢出部分不记录,只保存有效部分。
对于 -128,也就是 -1000,0000
。它的补码就是1,000 0000。
对于负数来说,补码就是符号位
1,后面是这个负数的补数
。
- 对于正数,其,原码=反码=补码
- 原码只是在真值的基础上加了一个符号位。
- 对于负数
- 反码:在原码基础上,符号位不变,数值位取反。
- 补码:在原码基础上,符号位不变,数值位取反,再加一。
- 对于移码
- 移码只针对整数,用于表示浮点数的阶码。
- 由于补码不能直观体现出数的大小。
- 移码和补码仅符号位相反,其他一样。
原码
原码表示简单易懂。
但进行运算时,就会出现问题。
例如:
1,010+1,001=0,011(-2+(-1)=3)
0,001+1,001=1,010(1+(-1)= -2)
0,001+1,010=1,011(1+(-2)= -3)
这说明,用原码去运算会出现逻辑上的错误,如0,001+1,001,不管符号位如何,数值位上永远是其对应的加法操作,想做的是1-1,但是数值位,他却在做1+1这件事。逻辑错误。
补码
先回到数制中,先看数
补数的概念
钟表指向8点,想要指向4,可以有两种方法。
逆时针转4,记为-4。
顺指针转8,记为+8。
二者达到了同样的效果。
8-4=4
8+8=16
这两件事情是一样的。因为钟表不会显示16,溢出12之后就是4。
模:|-4|+8=12
称8是-4以12为模的补数。
回到二进制数
中,这同样可以解决将二进制数中的减法转换为加法的问题
1011-1011=0000
1011+0101=10000,二者是一样的。(0101是 -1011的补数)
再来看1011-1100=-0001
1011+0100=1111,我们发现结果并不相等,但是 -0001的补数是1111,问题不大。
此时我们已经将二进制的减法成功的转化为了加法。
由这几个例子,得出
对于计算机而言,他并不知道通过将负数转换为补数
之后进行的运算,计算出的这个 C
到底对应的是正数还是负数。
因为既可以对应正数,也可以对应负数(上面的1111对应的并不是字面大小,而是 -0001)
为此,引入一个符号位去标记,(规定 0是正数,1是负数)
补数,加上一个符号位之后,在计算机中叫为补码。
假设我们这样去计算
1011-1100=0,1011+1,0100=1,1111 (这时就告诉计算机,得到的结果是一个负数)
1011-0010=0,1011+1,1110=0,1001 (这时告诉计算机,得到的结果是一个正数)
这样就很好的解决了问题
关于这个符号位是如何起作用的:
如果一个二进制数是 1111111
7个1,则对应的十进制就是 27 -1
如果一个二进制数是 11111111
8个1,则对应的十进制就是 28 -1
补码转换为真值:
符号位1,代表真值是负数,后面的二进制位是一个补数。
1000 0110
对应的真值-(27-6)就是 -27 + 6
1000 0100
对应的真值-(27-4)就是 -27 + 4
1000 0000
对应的真值-(27-0)就是 -27
IEEE754中E的范围是: 1~254
求负数的补码:
先求对应正数的补码, 然后进行求补运算, 即全部取反, 之后加一。
符号位是1, 后面是补数。
负数+负数:负溢
正数+正数:正溢