专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

原码,反码,补码相关

前言 :本来只是想简单记录一下,没想到好像学到了什么了不得的东西OvO

太长不看版

真值与机器数

在计算机中,我们使用 0 表示正数,1 表示负数。将最高位作为符号位,使用 0 或 1 表示正负的二进制数称为机器数,而原来的数称为真值

比如,如果我们有机器数 x = 01101,y = 10110,则其对应的真值分别为 x = +1101,y = -0110。

需要注意的是,二进制的位数是受机器设备的限制的。机器内部设备一次能表示的二进制位数叫做机器的字长,一台机器的字长是固定的。字长 8 位叫一个字节 ( byte ),机器字长一般都是字节的整数倍,如字长 8 位,16 位,32 位,64 位等等。

原码、反码,与补码

原码、补码、反码是机器数的三种表现形式。

原码

将数的真值形式中的 ” + ” 用 0 表示,” – ” 用 1 表示时,叫做数的原码形式,简称原码。

由此,当以机器字长为 4 位时为例,我们可以列出如下对应关系 :

正数 负数
0 0000 -0 1000
1 0001 -1 1001
2 0010 -2 1010
3 0011 -3 1011
4 0100 -4 1100
5 0101 -5 1101
6 0110 -6 1110
7 0111 -7 1111

原码的表示法比较直观,它的数值部分就是该数的绝对值,并且与真值、十进制的转换十分方便。但依然存在着一个问题 :当两数相加时,机器需要首先判断两数的符号是否相同,若相同,则绝对值相加,若不同,则绝对值相减。并且,在做减法之前,还需要判断两数绝对值的大小,然后用大数减去小数,最后再确定差的符号。

换言之,当使用原码这样一种直接的形式进行加运算时,负数的符号位不能与其数值部分一同参与运算,而必须为其设置额外的逻辑去处理,这就造成了麻烦。由此,引入了反码与补码的概念。

反码

反码的表示方法 :

  • 若机器数为正数,则反码与原码一致
  • 若机器数为负数,则反码是在原码基础上保持其符号位不变,其他位置取反
正数 原码 补码 负数 原码 补码
0 0000 0000 -0 1000 1111
1 0001 0001 -1 1001 1110
2 0010 0010 -2 1010 1101
3 0011 0011 -3 1011 1100
4 0100 0100 -4 1100 1011
5 0101 0101 -5 1101 1010
6 0110 0110 -6 1110 1001
7 0111 0111 -7 1111 1000

补码

补码的表示方法 :

  • 若机器数为正数,则补码与原码一致
  • 若机器数为负数,则补码是在反码的基础上加1,并舍弃溢出位
正数 原码 反码 负数 原码 补码 反码
0 0000 0000 -0 1000 1111 0000
1 0001 0001 -1 1001 1110 1111
2 0010 0010 -2 1010 1101 1110
3 0011 0011 -3 1011 1100 1101
4 0100 0100 -4 1100 1011 1100
5 0101 0101 -5 1101 1010 1011
6 0110 0110 -6 1110 1001 1010
7 0111 0111 -7 1111 1000 1001
-8 1000

值得注意的是,补码解决了原码与反码中“ 同时存在 +0 和 -0 ”的问题,从而使整个存储多出来一个位置。正是因为机器使用补码,所以对于编程中常用到的 32 位 int 类型,可以表示的范围为 [-2^31, 2^31 - 1]。其第一位为符号位,而使用补码时又可以多保存一个最小值。

写在后面

下面是一点解释和碎碎念。

首先需要理解的是“ 模 ”的概念。

还是拿经典的时钟表盘举例子,首先我们有一个钟表,它指向 4 点 :

91_1.png

如果我们要把指针拨到 “ 10 小时之后的时间点”,可以怎么做呢?一种方式是将指针向前(顺时针)拨 10 个单位,而另一种方式,则是将指针向后(逆时针)拨 2 个单位。

对于容量为 12 的时针来说, +10 和 -2 得到的结果是一致的。也即是说,虽然 4+10 这一运算超出了预设的位数 12,从而造成了溢出,但我们直接舍弃掉溢出的部分,依然能够得到正确的结果。

这里的 “12” 即是该计数体系的 。在这个有限容量的计数体系中,对于一个已知的数值 X ,在其的基础上 +10 和 -2 是完全相同的,故称 -2 和 +10 是关于模 12 的一组补数。这种将 X-2 转化为 X+(模-2) 的运算方式,正是计算机 “化减为加” 的基础。

因此,我们在有限的计数系统中做出了这种定义 :正数的补数为其本身,负数的补数 = 模 – 该负数的绝对值。一个数加上另一个数(不论正负),结果等于加上这个数的补数。如果在此过程中发生溢出,相加得到的数值超出了计数体系的最大容量,就可以像多转了一圈的指针一样,直接舍弃溢出的这一部分,而不会对结果的正确性产生影响。

符号位

在 8 位计算机中,一个字节可以表示 256 种状态。如果把字节看做一个钟,将分界点 -128 和 0 分别标在原表盘 12 点和 6 点所指的位置。当计算 120 D + 120 D 时,我们在 120 的基础上指针顺时针拨 120 个单位,当指针掠过 -128 这一分界点,数值由正数变为了负数,最终指向 -16 的位置。

91_2.png

这个时候再来查看二进制的计算方式,120 D + 120 D = 0111 1000 B + 0111 1000 B = 1111 0000 B,最高位接受来自地位的进位,说明该计算越过了 “分界点”,需要求其补数来得到正确结果。对 1111 0000 B 求补得到 1001 0000 B,即 -16 D,和上述推理一致。

引用 @张天行 的总结,“加法都是从地位往高位做的,如果两个数(补码)后七位相加产生了进位,说明发生了溢出。每当溢出一次,符号就要反一下,0 变 1,1 变 0。符号是 1 的,说明大得越界了,需要再求个补,用取值范围内的负数表示结果;符号是 0 的,说明小的越界了,但由于正数的补数就是本身,就不必再求补了。”

这是数学的自洽与和谐,令人兴奋的自然之美。这一点点内容断断续续拖了几天,期间拜读了好几位大神的回答,可能有点莫名其妙,但不知为何每一遍都让人心潮澎湃。不是由于规定了符号位,所以用最高位的 1 和 0 来表示正负,而是因为补码运算可以通过最高位来表示正负,所以符号位诞生了。补码它就在那里,并非被定义或发明;我们 “发现”了它。


内容参考 :www.zhihu.com/question/20…

文章永久链接:https://tech.souyunku.com/43657

未经允许不得转载:搜云库技术团队 » 原码,反码,补码相关

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们