关于补码.

文章作者:新注册送38元体验金编程 上传时间:2019-08-28

 

 

 


新注册送38元体验金,=============================

 

原码, 反码和补码.

原码表示方式(最高位作为符号位, 0 表示正数, 1 表示负数):



反码表示方式(负整数就是正整数按位取反):



补码表示方式(负整数是正整数按位取反再加 1):



 

 


=============================

 

不妨假设只有 4 个二进制位用来表示整数, 二进制从 0000 到 1111, 一共能表示 2 ^ 4 即 16 个整数. 把它们放到一个有 16 个刻度的表盘上:

新注册送38元体验金 1

图 1

图1 所示, 由于只有 4 个二进制位, 因此只有 16 种 位模式, 表盘上 16 个刻度每个刻度对应于一个 位模式. 很显然每个位模式可以用来对应表示一个整数. 而如果它们都用来表示正整数的话, 只能表示 0 到 15.

 

=========================

 

那怎么表示负数呢?

为了公平起见, 正数负数各分一半的刻度. 不妨将这个表盘切成两半, 一半表示正数, 一半表示负数. 如果我们规定最高位表示符号的正负, 那么能表示数值的位就只剩下 3 个二进制位, 3 个二进制位表示数值只能表示 8 个, 从 ** 这正是原码表示整数的方法:

新注册送38元体验金 2

图 2

图 2 所示. 这种表示方式在"规定"上看来很自然: 最高位是符号位, 剩下的是数值位. 其实不然: 原来用于表示正整数 8 的位模式 1000 现在用来表示 -0. 原来用来表示正整数 15 的位模式 1111 现在用来表示 -7. 如果我说, 在只有 4 个二进制位的情况下, 使用原码来表示整数(有正有负)时, 8 ==> -0, 15 ==> -7, 11 ==> -3, ...(而不是告诉你最高位作为符号位什么的, 忘掉符号位的规定), 你会不会(像补码表示一样)感觉到有点 "make no sense" 呢.

在原码表示法中, 0 有两种表示, 0000 和 1000, 即 0 和 -0.

 

          4. 表示正数 / 负数的第二种方案, 反码

 

想法是一样的: 把表盘切开, 各分一半. 只不过这种各分一半的分法是直接将 位模式 取反 -- 每个位模式都有一个相反的位模式不是么:

新注册送38元体验金 3

图 3

图3 所示. 原本用来表示正整数 15 的位模式 1111 现在用于表示 -0. 原本用来表示正整数 8 的位模式现在用于表示 -7. 同样, 在反码表示法中, 0 有两种表示, 0000 和 1111, 即 0 和 -0.

one's complement. 为什么叫 one's complement 呢?

**. 如果用另外一种方式来表示取反过程的话**:





我们发现对一个数 n 取反的操作等价于用所有位都为 1 的数减去 n. 再看看反码表示法中, 1111 这个位模式用来表示多少呢, 表示 . 再看将 的位模式 取反后得到的位模式 用来表示多少呢? ** 也就是说如果我们使用 one's complement 这种表示法的话, 可以很自然的(通过位模式相减)得到 -0 - 5 == -5 这样的等式, 这是使用原码表示法所做不到的事情哦!(比如原码的 -0为 1000, 5 为 0101, 1000 - 0101 == 0011, 而 0011 在原码中表示 3).然而由于在反码表示法中 0 有 0 和 -0 两种表示, 我们可以得到 -0 - 5 == -5 这个等式, 却得不到 0 - 5 == -5 的等式.**

 

           5. 表示正数 / 负数的最终方案, 补码

 

新注册送38元体验金 4

图 4

图4 所示, 这就是补码表示法啦. ** 原本用于表示正整数 15 的位模式 1111 用于表示 -1. 原本用于表示正整数 8 的位模式 1000 现在用于表示 -8. 0 只有一种表示方式, 就是 0000.** 即在这种表示法中, 15 ==> -1, 8 ==> -8, 12 ==> -4, 这个突然就 "make no sense" 了? 那对原码表示法为什么没有突然 "make no sense" 呢... 大约因为某个扯淡"定理"比较容易让人脑子短路的原因吧...

two's complement. 原因很简单, 同样以 5 为例:





** 表示 5, 位模式 ** 表示 . 位模式(共 5 位) 呢? 它无法在我们的表盘上表示. 然而如果我们非要在表盘上表示它的话, 那么我希望你能理解, **(可以想象一个时针, 每向前走一个刻度表示 1, 在这个表盘上, 当它到达 16 时又归零. 实际上就是 % 16. (mod 16, 模 16 运算)).

在补码表示中, 我们很自然地(通过位模式相减)得到了 0 - 5 == -5. 由于补码表示法中表示 0 的方法只有一种, 所以它没有反码的 0 和 -0 的问题.

 

"一个负整数的补码表示 等于将 其所对应的正整数的补码表示 取反再加一" 这个扯淡 "定理".

5 的补码表示为 , 则 的补码表示为 ** (~ 表示取反, C 语言中的按位取反运算符).








1111 就是补码表示中的 -1. 补码表示中的 -1 是通过位模式 0000 - 0001 得到的(忽略借的一位, 那位在表盘上是不可表示的).

** 这个"定理"了.

 

=========================

 

新注册送38元体验金 5

图 5

图5 所示. 时针从 走到(如果我们坚持认为这个表盘一半的位模式表示负数一半表示正数并采用补码表示), 或者从 走到 (如果我们认为所有的位模式都用来表示正数), 好吧更明确地说**, 可以走两条路, 逆时针走 格, 或者顺时针走 格**. 如果逆时针表示减法而顺时针表示加法的话, 那么我们有:



只有 4 位二进制位的情况下的)补码表示法中, 既然 -4 和 12 的位模式是一样的, -3 和 13 的位模式也是一样的, -7 和 9 的位模式也是一样的, 那这两种运算实际上没有差别. 实际上 **共模的模是 16.**

怎么解释内存中的一个位模式究竟是正数? 还是看着负数? 是软件的事情. 当然计算机在运算过程中同样会依据运算的结果进行是否进位/借位的置位. 软件可以通过标志位进行判断. 由于补码这种表示形式可以简化硬件电路的设计, 因此现在的计算机表示整数基本都使用补码表示形式.

 

如果用 1 个 Byte 表示一个整数, 那么其模是 2 ^ 8; 如果用 4 个 Byte 表示一个整数, 那么其模是 2 ^ 32. 这种情况下只需要画一个更加大的表盘, 有更精细的刻度就可以了, 其基本解释和只有 4 位表示一个整数的情况是一样的.

 

 

, 反码和补码 . 原码表示方式(最高位作为符号位, 0 表示正数, 1 表示负数) : 反码表示方式(负整数就是正整数按位取反) : 补码表示方式...

本文由新注册送38元体验金发布于新注册送38元体验金编程,转载请注明出处:关于补码.

关键词: