文章理解自这里
前提:计算机的运算器中只有加法器没有减法器。数据在计算机中是二进制表示的。
想当然的原码
表示法:
1:用符号位区分正负数
2:正数-正数 == 正数 + 正数的相反数:1 - 1 = 1 + (-1) = 0
假如我们有一个4位的机器,因为数字有正负数和零值,因此想当然的我们把最高位设置为符号位0代表正数,1代表负数,后面位为二进制数值的表示,例如1:0001,-1:1001,这种表示法即为原码。
下面我们来验证原码表示法的实用性:
正数+正数:0001+0010=0011 (1+2=3)
√
零 + 零:0000+1000=1000 (+0+(-0)=-0)?
正数加负数:0001+1001=1010 (1+(-1)=-2)×
从结果中我们发现,当没有减法器时这种想当然的数值存储方法(原码)并不能正确的计算减法。
那怎么办呢?
利用同余概念的补码
表示法:
在原码表示法中我们试图使用加一个数的相反数的方法解决减法问题,却碰了壁。还有没有可以避开减法器的加法操作呢?是有的,那就是同余法。
基础概念
模:这里的模可以理解成可以表示的数的个数。比如四位二进制,可以表示0000——1111,共16个数,那么就是模16。一位二进制最大可以表示的数是1,但是可以表示两个数,所以模2。
同余数:当前数 + 当前数的同余数 = 模, 同余数 = 模 - 当前数
基本思想
对于数值有限制,有溢出的运算(模运算)来说,减去一个数,其实也相当于加上这个数的同余数。
栗子:
如果说现在时针现在停在10点钟,那么让它指向八点钟呢?
方法1:10点 - 2(小时) = 8(点),也就是倒回去(减去)两个小时。
方法2:10点 + 10(小时)= 8(点),也就是走到明天8点。这里的模就是12小时。
存储表示:
- 不需要符号位
- n 位存储的模 = n 2 n^2 n2:
来看一下这种表示方法的实用性:
正数 + 正数:0110 + 0010 = 1000 (6 + 2 = 8)
√
正数 + 同余数:0110(6
)- 0010(2
)=0110(6
)+ 1110(14
)=10100(20
)×
:因为是4位存储,所以只能得到0100 = 4 ,所以√
看来。。。还是错的。但是!我们看到按照这种算法得出的结果是10100,但是对于四位二进制数,最大只能存放4位(硬件决定了),如果我们低四位,正好是0100(4),正好是我们想要的结果,至于最高位的‘1’,计算机会把他放入psw寄存器进位位中。8位机则会放在cy中,x86会放在cf中(这个我们不作讨论)
简略记忆:
原码
最高位为符号位,0代表正数,1代表负数,非符号位为该数字绝对值的二进制表示。
如:
127的原码为0111 1111
-127的原码为1111 1111
反码
正数的反码与原码一致;
负数的反码是对原码按位取反,只是最高位(符号位)不变。
如:
127的反码为0111 1111
-127的反码为1000 0000
补码
正数的补码与原码一致;
负数的补码是该数的反码加1。
如:
127的补码为0111 1111
-127的补码为1000 0001
总结一下就是:
正数的原码、反码、补码是一致的;
负数的补码是反码加1,反码是对原码按位取反,只是最高位(符号位)不变;
计算机数字运算均是基于补码的。
题目:
1.由3 个“1”和 5 个“0”组成的 8 位二进制补码,能表示的最小整数()
正确答案: B 你的答案: 空 (错误)
-126
-125
-32
-3
求int的最大最小值,不使用头文件:
/// int32时,16进制为4位一个值,32 / 4 = 8;
/// 当求最大值时(正数的原码、反码、补码都一样),最高位(符号位)置0,代表正数,其余位均为1.
/// 当求最小值时,采用补码表示的最小值为32个1,即,1111 1111 1111 1111 1111 1111 1111 1111
.此值的反码为末位减一,即1111 1111 1111 1111 1111 1111 1111 1110
.补码为除符号位取反即1000 0000 0000 0000 0000 0000 0000 0000
= (16进制表示:0x80000000
)
int main() {
int Max = 0x7FFFFFFF;
int Min = 0x80000000;
cout << Max << " " << Min << endl;
// 2147483647 -2147483648
return 0;
}