前言
在整型数据类型的取值范围中,一个值得注意的特点是取值范围并不是对称的——负数的范围比整数的范围大1。具体点说,对于有符号的数据类型(例如8位),表示范围是-128-127,为什么不是-127-127?或者-127-128呢?
一、一句话结论
这与补码的编码方式有关系。默认的计算机中有符号数的编码方式都是补码,而补码的表示范围就是-128 ~ 127(8位),当然也有其他编码方式:反码和原码,如果一个计算机中采用了反码和原码的编码方式,那么表示范围就只能是-127 ~ 127。
二、为什么?从权重的角度来分析
假设一个整数数据类型有w位:x = [xw-1, xw-2, …, x0], 对于无符号数,我们用一个函数 B2Uw (Binary to Unsigned)来表示:
对于有符号数,最常见的有符号数的计算机表示方式是补码形式(two’s complement)。在补码中,将最高有效位 xw-1 解释为负权(negative weight),用函数 B2Tw (Binary to Two’s-complement)来表示一个有符号数:
最高有效位 xw-1也称为符号位,它的“权重”为 -2w-1 。当 xw-1为0时,表示非负数,最大值为0111_1111,即127;最小值为0000_0000,即0,非负数表示范围为0-127。当 xw-1 为1时表示负数,最小值是1000_0000,即-128+0=-128;最大值是1111_1111,即-128+(0111_1111)=-1,负数表示范围为-128 ~ -1。总体来说,表示范围是-128~127。
三:拓展
除了补码以外有符号数的其他表示方法:反码和原码。
反码(Ones’ Complement):除了最高有效位的权是 -(2w-1-1) 而不是 -2w-1 外,它和补码是一样的:
原码(Sign-Magnitude):最高有效位是符号位,用来确定剩下的位应该取负权还是正权:
这两种表示方法对于数字0都有两种不同的编码方式。原码中,0000_0000和1000_0000都表示0;反码中,0000_0000和1111_1111都表示0。正是因为原码、反码中都用了两个编码来表示0,所以取值范围都少一个:-127~127。而补码中因为编码方式的原因表示范围是-128 ~ 127。
参考
《深入理解计算机系统》,机械工业出版社,P38~43.