原码
第一位为符号位,后面的为数字的二进制表示。
eg: 127 和 -127 的 8位原码为 [0111 1111, 1111 1111]
反码
正数的反码为其原码;负数的反码,符号位不変,后面的取反。
eg: 1的8位原码和反码为 [00000001]原 = [00000001]反
-1的8位反码为 [10000001]原 = [11111110]反
补码
正数的反码为其原码;负数的补码为其补码+1
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
为什么用补码
将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.
然而,如果使用原码运算:
计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
结果不正确,如果用反码的话:
1-1=0
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反
= [1000 0000]原
= -0
结果的真值部分是正确的. 而唯一的问题其实就出现在”0”这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.于是补码的出现, 解决了0的符号以及两个编码的问题:
1-1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]补 + [1111 1111]补
= [0000 0000]补
=[0000 0000]原
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:
(-1) + (-127)
= [1000 0001]原 + [1111 1111]原
= [1111 1111]补 + [1000 0001]补
= [1000 0000]补
INT_MAX & INT_MIN
这就是为什么C++ 中 INT_MAX 是2147483647 , 而INT_MIN是 -2147483648
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
这里没有简单地将INT_MIN赋值成 -2147483648,是因为-2147483648对于编译器而言是个表达式,而2147483648对于32-bit整数是无法表示的,在计算机中以原码的形式表示为 10000…0000(31个0)。
Reference
http://blog.csdn.net/u011080472/article/details/51280919
http://blog.csdn.net/seizef/article/details/7605010