http://bbs.chinaunix.net/thread-3765224-1-1.html
很对, 没有问题. 不过我想告诉LZ一个更容易理解的办法. 假设, 我现在只有4 bits空间. 那么这个空间最多能存放2 ^ 4, 即16个数, 也就是 0 - 15. 想像一个表盘, 这个表盘刚好有16个刻度. 这样子, 我们将上面的16个数和表盘对应起来. 对应的结果如下所示. | | 0000 1111 0001 1110 0010 1101 0011 1100 0100 1011 0101 1010 0110 1001 0111 1000 | | 本来表盘是圆形的, 结果上面看上去是菱形的. 将就看吧. 瞧: 这个表盘能够表示16个数字, 所以我们称呼16为这个表盘的模. 同理, 我们称16是4bits的模, 256是8bits的模, etc. 看到上面和下面我分别标的竖线了吗? 那代表我将这个表盘切成了两部分. 这个切法代表什么意思呢? 我们知道表盘能够表示16个数字, 如果我认为这个表盘表示的数字都是正数, 那么我可以不切这个表盘. 不切这表盘就表示, 假设时针从0开始顺时针转, 每过一个小时, 时针就向前一格(假设一天有16个小时, 这也不是什么大事, 呵呵). 于是, 这个表盘可以表示 0 -- 15. 现在我想让这个表盘既可以表示正数, 也可以表示负数. 看, 很简单, 我把这个表盘像上面那样切开, 就像切一个馅饼一样. 我说左半部分你们代表正数吧. 右半部分你们代表负数吧. 于是一切就work了, 我们让时针顺时针转, 顺时针走一格就代表加1. 我们让时钟逆时针转, 逆时针走一格就代表减1.瞧, 正着转一格, 0000 -> 0001. 逆时针转一格, 0000 -> 1111, 等等, 1111是什么? 没错, 1111就是补码的-1. 看, 这个表盘完美地工作, 太妙了. 现在我们来做一件事情. 假设现在时针指向12点(注意, 我们这个表盘一共有16点), 就是指向1100那里. 现在我们想让时钟指到9点, 也就是1001那里. 我们可以用两种方式来做到这一点: 第一种方式是倒拨(逆时针方向)3格. 于是我们有: 12 - 3 = 9. 第二种方式是顺拨13格. 于是我们有: 12 + 13 = 9. 我们看看, -3是谁? 假设我们切开了这个表盘, 那么-3就是1101. 我们再看看, 13是谁? 假设我们没有切开这个表盘, 看, 13也是1101. 于是我们有: 1100 + 1101 = 1001 于是, 明白了吗, 我不需要12 - 3, 那个减号对我来说没用. 我只管知道 1100 + 1101 = 1001就可以了. 没错, 计算机为什么用补码来表示整数,因为用补码来表示整数不需要减法, 我们只要一个硬件加法器就可以了. 同时, 我们还发现一件事情. (12 - 3) % 16 == 9 (12 + 13) % 16 == 9 我们称, 12 - 3 和 12 + 13 共模同余(模16余9), 同时称, 13和3互补(在模为16的前提下), 即互为补数. 看, 算补码也很简单了. 当然了, 比如假设有32 bits, 那么模就是2 ^ 32, 如果有64 bits, 那么模就是 2 ^ 64. 很简单, 我们只需要想象一个大得多的表盘就可以了, 这挺简单的, 不是吗? |