void main(){ unsigned int a=3,b=4; printf("%d",(a-b)/2); }
一个BC上面的小程序,有同学问我,为什么等于32767。考虑到大家后天就要考试了,在此我尽可能向大家把这个问题说清楚。
1 原码,反码和补码
原码
如果机器字长为n,那么一个数的原码就是用一个n位的二进制数,其中最高位为符号位:正数为0,负数为1。剩下的n-1位表示概数的绝对值。
计算机中,正数存原码,负数存补码!!
正数的原码、反码和补码都是原码,或者说,正数只有原码!!当题目要你求一个正数的原码、补码或者反码时,只要算原码就可以了!!!
例1. 5[原] = 0000,0000,0000,0101;一共16位,其中第一位是符号位“+”,实际存储中,左边第一位使用0来代表“+”。
例2. -5[原] = 1000,0000,0000,0101;一共也是16位,其中第一位为符号位“-”,实际存储中,左边第一位使用1来代表“-”。
反码
反码就是在原码的基础上,符号位不变其他位按位取反(就是0变1,1变0)就可以了。只对负数有用!
例3 5[反]= 0000,0000,0000,0101;前面说了,正数的反码就是原码!
例4 -5[原] =1000,0000,0000,0101;因此,符号位的1不变,其他全部取反,得到了 -5[反]=1111,1111,1111,1010;
补码
补码也非常的简单就是在反码的基础上按照正常的加法运算加1。只对负数有用!
例5 5[补]=0000,0000,0000,0101;前面说了,正数的补码就是原码!
例6 -5[反]=1111,1111,1111,1010;因此,补码是在反码的基础上加1,得到了 -5[补]=1111,1111,1111,1011;
2 有符号数和无符号数
刚才介绍的原码、反码和补码。正数原码,负数补码就有符号数的计算机存储格式。而对于无符号数,无符号数都是正数,因此,无符号数在计算机中存储时,是没有符号位的!有符号数存储时,是1位符号位,15位数据位。无符号数直接就是16位数据位,直接转换成2进制即可!也因为这样,无符号数的可储存最大值是有符号数的2倍+1。
不管是有符号数还是无符号数,在计算机中,都存成了16位的结构。因此,同样的一串二进制,翻译成有符号数和翻译成无符号数可能就代表不同的数字!下面我将举例说明:
例7 0000,0000,0000,0001在有符号和无符号中各代表什么数?
解:无符号中,直接把这16位看成2进制数,转换成10进制后,就是1。在有符号中,第一位是0,剩下的15位转化为2进制,仍然是1。
总结:当第一位是0时(也就是有符号数为正数时),16位比特位翻译成有符号数和无符号数,代表的是同一个数。
例8 1000,0000,0000,0001在有符号和无符号中各代表什么数?
解:对于无符号数,注意,第一位不是符号位,而是代表2^15,因此,翻译成无符号数的值是2^15+2^0=32769。而对于有符号数,第一位是符号位,代表负“-”。因此,这是一个负数存成了补码的形式。如何将这个补码翻译成这个负数的值。我们需要反向操作。负数存成补码的过程是负数-原码-反码-补码,这里,反向操作,将这串二进制减1、取反则变成了原码。负数的原码就是1111,1111,1111,1111;注意,取反的时候符号位也是不要动的!原码的第一位是符号位“-”,实际值就是2^14+2^13····+2^1 = 32767
3 问题解答
4 增补拾遗
这道题讲道理还是有点难的=。=我觉得大家搞不定也不要紧,也就两分,大部分的题目没这么难,这其实已经算是计算机组成原理的课程了,有点超纲。下面简单介绍一点额外的知识。
补全
补全分为有符号补全和无符号补全,对于无符号数的左移和右移,空出来的皆补0.而对于有符号数,右移之后,左边空出来的补与符号相同;左移时符号位不变,右边补0。(不用记了 用不到的···)
整数除法
两个int相除,也就是取模(与余数不同,是向0靠拢,具体百度),1/2=0,2/2=1,3/2=1;-1/2=0;C语言中,刚才我"/2"用的是右移操作,直接将1步的 1111,1111,1111,1111 翻译成无符号数65535,然后取模计算“/2”得到32767是一样的操作。