原码反码补码

Endless_daydream Lv4

整数

表示法

正数 负数
真值 6 -6
原码 0 000 0110 1 000 0110
反码 0 000 0110 1 111 1001
补码 0 000 0110 1 111 1010

正数的表示相同,区别在负数上:

原码:对正数表示的最高位(符号位)取反。

反码:对正数表示的所有位取反。

补码:对正数表示的所有位取反,再当成普通二进制数加一(不区分符号位和其他位)。舍去溢出。

移码:把中间的数移为0

原码是最接近人类的表示思维,打标记,分类处理。

但是这样光是加法就有 正+正 / 正+负 / 负+负 三种情况要分类处理,对于计算速度不友好。

反码希望解决这个不统一的问题,解决思路很简单:对于负数,把所有位取反,得到1111…1-|负数|,那么随着绝对值的增长,正数和负数对称地从0向两边增长,这样正数加负数就正好相互抵消,于是可以统一处理加法。

但是它太过简单,以至于有很大的问题:对0取负,反码表示为 1111 1111,也就是说0同时有0000 0000和1111 1111两种表示(1111 1111就是0也说明了为什么负数表示为111…1 - 绝对值 有合理性)。了解代数的同学会知道,这直接导致加法没有单位元,不能成为同时能应用于正数和负数的运算。举个例子,任意数x加0应该还是它自己,但任意数x的二进制表示加1111 1111就不是它自己了。

补码延续这个思路解决了问题,它对负数的反码表示加一,让1111 1111溢出舍去,这样0的正数和负数又重合为一个0000 0000了。相当于把负半轴从0开始整体搬一位,让-0和0重合。因为只动了负半轴,所以从真值到补码的映射需要正负分开讨论,但映射到补码空间后,补码表示下的正数和负数运算不需要分开讨论

注意到这样必然会有另一个数也和自己的负数补码表示相等,它是1000 0000,由目前合法的最大正数0111 1111加一或者最小负数1000 0001减一(加-1的补码1111 1111)得到,我们让它来表示最大正数或者最小负数都可以,不影响加法群的性质。计算机中让它表示最小负数$-2^{31}$,以便可以通过符号位判断是不是负数。

于是我们重新得到了加法群(本来自然码是0到$2^{32}-1$(1111 1111)的加法群,由补码表示映射到了$-2^{31}$到$2^{31}-1$的加法群)

如果我们不考虑演变,有更简单直达结果的方式:

考虑加法群$Z_{2^n}={0, …, 2^n-1}$,将后一半的数解释为其加法逆元的负数。

补码就是这种解释映射的数学写法。

小数

定点小数

已知小数点位置,也就是已知小数位数,则只需要按整数表示来,然后右移相应位数即可。

浮点小数

分为阶码和尾数部分,总长度固定即可。

阶码是整数,尾数是定点小数。

规格化:约定定点小数的表示范围,将不在这个范围的小数左右移到这个范围中,其中右移会有精度损失。

IEEE标准:

阶码是移码,尾数是补码,阶码放在尾数符号位和数值位之间。

  • Title: 原码反码补码
  • Author: Endless_daydream
  • Created at : 2024-03-15 11:53:26
  • Updated at : 2024-03-15 15:03:31
  • Link: https://endless_daydream.gitee.io/2024/03/15/cpp/原码反码补码/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
原码反码补码