c语言源码补码机器码的定义,几种机器码(原码、反码、补码)应该这样理解...

由于觉得机器码中“原码”、“反码”和"补码"这样的概念过于蛋疼,参考一些博客和问答之后,决定调整优化内容便于回顾,参考链接已经放在文章底部。如果内容有误,或者你有独到的见解,也欢迎你提出来。

二进制的概念

大家都知道尺子吧,小学开始就在使用的测量距离的工具。现在我允许你以厘米(cm)为唯一的单位,制作一定长度的尺子。例如,我可以制作 1cm 的尺子、2cm 的尺子,那么我可以用这两种长度的尺子作为刻度来测量三种长度:1cm、2cm 和 3cm(3=1+2)。有人会问为什么我不能先量 1cm 再量 1cm,逐渐累积到指定的目标呢?在这里我们规定:每个尺子在一次测量中无法重复使用多次。

有了以上的概念,我们来考虑一个问题:

至少需要制作多少把尺子,可以表示从 0 ~ 15 cm 之间的任意厘米长度?(当然,0 在实际中不需要考虑)

a81337da6e86b6e4365fb6796929b4d2.jpe

答案是 4 把,分别是 1cm,2cm,4cm 和 8cm. 不信?我们在下面的表格中列举出所有的情况,其中如果一个尺子被使用了,我们用 1 作为标记,没被使用则用 0 作为标记。

长度

8cm

4cm

2cm

1cm

二进制

0

0

0

0

0

0000

1

0

0

0

1

0001

2

0

0

1

0

0010

3

0

0

1

1

0011

4

0

1

0

0

0100

5

0

1

0

1

0101

6

0

1

1

0

0110

7

0

1

1

1

0111

8

1

0

0

0

1000

9

1

0

0

1

1001

10

1

0

1

0

1010

11

1

0

1

1

1011

12

1

1

0

0

1100

13

1

1

0

1

1101

14

1

1

1

0

1110

15

1

1

1

1

1111

可经过验证,这的确是这个问题的最优解。

继续思考这个问题,如果将长度的表示范围增加到 10000,需要多少把尺子?这篇博文不是为了详解二进制,这里只给大家一个直观的理解。

计算机中的二进制

早期的电子元件只能表示开(1)和关(0)两种状态,所以计算机就采用了“二进制”,这样设计的可行性很高,比如开关的接通和断开、晶体管的导通和截止、磁原件的正负剩磁、电位电平的高低等都可以表示 1 和 0 两个数。另外使用二进制运算,规则简单,可靠性高。

原码、反码和补码

先简单引用一下书上的概念:

原码表示法是机器数的一种简单的表示法。其符号位用 0 表示正号,用 1 表示负号,数值一般用二进制形式表示。

机器数的反码可由原码得到。如果机器数是正数,则该机器数的反码与原码一样;如果机器数是负数,则该机器数的反码是对它的原码(符号位除外)各位取反而得到的。

机器数的补码可由原码得到。如果机器数是正数,则该机器数的补码与原码一样;如果机器数是负数,则该机器数的补码是对它的原码(符号位除外)各位取反,并在未位加1而得到的。

好像多了一些概念,比如之前提到的二进制,以及看上去很玄乎的“符号位”。补码里面取反加一的操作,对于机器来说实在方便。如果单单地记住结论,拿去做题,当然没有问题,但想要了解一个知识的细节,最好还是追根溯源,搞清楚相应的概念是如何产生的。

原码的产生

回想一下之前尺子的例子,在自然界中,测量长度永远是正数,不可能存在长度为负的物体。我们数柴犬的时候,也是一只柴犬、两只柴犬,诸如此类。所以在计算机中存储的数字,都是没有符号的(unsigned)。但如果有人欠了你一些钱,该如何表示欠债的数量呢?人们为了面对这种情况,发明了正负符号,因此符号的概念很自然地被引入了计算机的数值表示。人们选择在最高位补上一个“符号位”,0 表示正号,1 表示负号。

正数

原码

负数

原码

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,负数符号位为 1,计算机中存储、处理、运算的数据通常是 8 位、16 位、32 位或 64 位的,这里以最简单的 4 位为例讲解。注意符号位是包含在 4 位中的其中 1 位,故可直观读出的数只有 3 位(只有后 3 位数可以按权展开)。

反码的产生

这里需要指出:计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行。即:减去某个数字(或者说加上某个负数)的运算,都应该研究如何用加法来完成。根据原码的表示,1(0001) + -1(1001) = -2 (1010),而实际结果应该为 0,这样的设计存在着问题。为了使得相反数相加结果为 0,人们发明了“反码”。反码表示方式是用来处理负数的,符号位置不变,其余位置相反。

正数

原码/反码

负数

原码

反码

0

0000

-0

1000

1111

1

0001

-1

1001

1110

2

0010

-2

1010

1101

3

0011

-3

1011

1100

4

0100

-4

1100

1011

5

0101

-5

1101

1010

6

0110

-6

1110

1001

7

0111

-7

1111

1000

至此,相反数相加不为 0 的问题成功解决!但是,还有一个问题没有解决。

补码的产生

在原码和反码中,0 居然都有两种表示方式,+0 和 -0,哪个才是正统表示?为了完成这个最后的目标,人们又发明了“补码”,在反码的基础上 +1.

正数

原码/反码

负数

原码

反码

补码

0

0000

-0

1000

1111

/

1

0001

-1

1001

1110

1111

2

0010

-2

1010

1101

1110

3

0011

-3

1011

1100

1101

4

0100

-4

1100

1011

1100

5

0101

-5

1101

1010

1011

6

0110

-6

1110

1001

1010

7

0111

-7

1111

1000

1001

反码中的 -0 在加上 1 之后,变成了 (10000) ,舍弃最高位后与 0 的反码表示完美契合。因此两个相反数相加时,去掉最高位的 1,也能得到 0000.

换一个角度

数学角度,将负数用补码表示,实际上是实现了一种从 [-128, 127] 到[ 0, 255] 的映射。如下所示:

数值

映射值

二进制

127

127

01111111

4

4

00000100

3

3

00000011

2

2

00000010

1

1

00000001

0

0

00000000

-1

255

11111111

-2

254

11111110

-3

253

11111101

-4

253

11111100

-128

128

10000000

如果你想利用数轴来理解,不妨认为负数部分的数段 [-128, -1] 被移动拼接到了 [128, 255] 的位置,然后根据 0 - 255 的二进制表示来依次赋值。

模与补数

在日常生活当中,可以看到很多这样的事情:

把某物体左转 90 度,和右转 270 度,在不考虑圈数的条件下,最终的效果是相同的;

把分针倒拨 20 分钟,和正拨 40 分钟,在不考虑时针的条件下,效果也是相同的;

把数字 87,减去 25,和加上 75,在不考虑百位数的条件下,效果也是相同的;

上述几组数字,有这样的关系:

90 + 270 = 360

20 + 40 = 60

25 + 75 = 100

式中的 360、60 和 100,就是“模”。

式中的 90 和 270、20 和 40,以及 25 和 75,就是一对对“互补”的数字。

知道了“模”,求某个数字的“补数”,就是轻而易举的了:

如果模为 365,数字 120 的补数为:365 - 120 = 245。

用补数代替原数,可把减法转变为加法。出现的进位就是模,此时的进位,就应该忽略不计。

二进制数的模

前面说过的十进制数 25 和 75,它们是 2 位数的运算,模是 100,即 1 的后面加上 2 个 0。如果有 3 位数参加运算,模就是 1000,即 1 的后面加上 3 个 0。这里的 1000,是十进制数的一千,可以写成 10^3,即 10 的 3 次方。推论:有多少位数参加运算,模就是在 1 的后面加上多少个 0。

对于二进制数字,模也是这样推算。如果是 3 位二进制数参加运算,模就是 1000,即 1 的后面加上 3 个 0;那么当 8 位二进制数参加运算,模就是 1 0000 0000,即 1 的后面加上 8 个 0。16 位二进制数参加运算,模可就大了,是 1 的后面加上 16 个 0。注意:这里提到的 1、0,都是二进制数。8 位二进制数的模可以按照十进制写成 2^8,即 256。16 位数二进制数的模,就是 2^16,按照十进制,它就是 65536.

据此理解反码与补码

所谓反码,英语里又叫 ones' complement(对一求补),这里的一,本质上是一个有限位计数系统里所能表示出的最大值,在 8 位二进制里就是 11111111,在 1 位十进制里就是 9,在 3 位十六进制里就是 FFF(再大就要进位了)。求反又被称为对一求补,用最大数减去一个数就能得到它的反,很容易看出在二进制里 11111111 减去任何数结果都是把这个数按位取反,0 变 1,1 变 0,所以才称之为反码。

所谓补码,英语里又叫 two's complement(对二求补),这个二指的是计数系统的容量(模),就是计数系统所能表示的状态数。对 1 位二进制数来说只有 0 和 1 两种状态,所以模是 10 也就是十进制的 2,对 7 位二进制数来说就是 10000000,这个模是不可能取到的,因为位数多一位。用模减去一个数(无符号部分)就能得到这个数的补,比如 10000000-1010010 = 0101110,事实上因为10000000 = 1111111 + 1,稍加改变就成了(1111111-1010010)+1,所以又可以表述为先求反再加 1. 总结求补码的方法就是正数依旧不变,负数保留符号位不变,先求反码再加上1.

所以求取补码,就按照定义的规定,负数采用“模减去绝对值”的方法来求,这是求补数的通用方法,适合于各种进制、各种大小的数字。“求反加一”的计算方法只是适用于计算二进制形式的补数,它并不是通用的,而且把“求反加一”用于求 128 的补码,有个溢出的现象,很多人都在这里郁闷了很久。取反加 1 就是为了让逻辑门电路能方便的计算,这样就不存在减法了。至于人的计算,或者说对于理解补码的原理,取反加 1 只会让人糊涂。

参考链接

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 根据题目,机器字长为8位,因此需要用8位二进制来表示这些字的不同表示。 1. -1的表示: - 原码:10000001 - 反码:11111110 - 补码:11111111 - 移码:10000000 2. -1011001的表示: - 原码:11101001 - 反码:10010110 - 补码:10010111 - 移码:11101000 3. 1011001的表示: - 原码:01011001 - 反码:01011001 - 补码:01011001 - 移码:01011001 其中,原码表示是最基本的二进制表示,正原码补码相同,而负原码最高位为1。反码是将原码中除符号位以外的位按位取反得到的。补码是将反码末位加1得到的,是计算机中负的标准表示方式。移码是将补码中所有位加上一个固定值得到的,在计算机中常用于浮点的表示。 ### 回答2: -1的原码表示为:10000001 -1的反码表示为:11111110 -1的补码表示为:11111111 -1的移码表示为:01111111 -1011001的原码表示为:11010111 -1011001的反码表示为:10101000 -1011001的补码表示为:10101001 -1011001的移码表示为:00101001 1011001的原码表示为:1011001 1011001的反码表示为:1011001 1011001的补码表示为:1011001 1011001的移码表示为:0011001 设机器字长为8位,表示范围为-128 ~ 127。可以发现上述三个目前都是负,而负在计算机中是用补码表示的。所以需要将这三个原码转换为补码来表示。 对于原码转换为补码的方法为: 如果原码的符号位为1(表示负),则补码不变; 如果原码的符号位为0(表示正),则补码等于原码。 对于补码转换为反码的方法为: 如果补码的符号位为1(表示负),则反码等于补码除符号位外的位取反; 如果补码的符号位为0(表示正),则反码等于补码。 对于补码转换为移码的方法为: 将补码的符号位取反得到移码。 因此,给出的三个补码和移码与原码是一样的。 ### 回答3: -1的8位原码表示为:10000001 -1的8位反码表示为:11111110 -1的8位补码表示为:11111111 -1的8位移码表示为:10000000 -1011001的8位原码表示为:11011001 -1011001的8位反码表示为:11100110 -1011001的8位补码表示为:11100111 -1011001的8位移码表示为:11111110 1011001的8位原码表示为:00110001 1011001的8位反码表示为:00110001 1011001的8位补码表示为:00110001 1011001的8位移码表示为:00110001 在8位的机器中,正原码反码补码和移码表示都相同。而负反码表示为对其原码除符号位外的每一位取反,补码表示为对其原码除符号位外的每一位取反,然后再加1。 移码表示是为了简化负的运算,将其转换成的在同等位上的正运算。移码的规则是对补码取反得到移码,正的移码与原码相同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值