一、二进制前置知识

1.十进制和二进制的转换

十进制转换二进制----除基取余法

例如:(55)转换为二进制

用55除2,得到27余1,------1

再用27除2,得到13余1,------1

再用13除2,得到6余1,------1

再用6除2,得到3余0,------0

再用3除2,得到1余1,------1

再用1除2,除不了余1。------1

把余数从下往上取,即 110111 = 55

二进制转十进制----位权法

例如:(110111)转换为十进制

【计算机原理】二进制的原码、反码、补码_补码

 


 

 二、硬件知识

任何数据都是以二进制存储在计算机中。

根据冯·诺依曼提出的经典计算机体系结构框架,一台计算机由运算器、控制器、存储器、输入和输出设备组成。其中,运算器只有加法运算器。

计算机虽然没办法做减法,但是可以加上这个数的相反数呀。但是二进制我们不能给它加上负号,于是我们需要引入一个符号位,存储在最左边的一位上,0代表正数,1代表负数。例如一个四位二进制数,最左边是符号位。0001,表示他是+1,1001,表示他是-1。


三,原码

终于到正题了,想象你是当年设计计算机的科研人员。你把带符号位的四位二进制数做运算,向全世界展示你精妙绝伦的设计--符号位。

于是你开始了计算----

  • 0001+0010=0011    1+2=3
  • 1000+0000=1000    (-0)+0=(-0)
  • 0101+1010=1111    5+(-2)=-7

 你突然发现,正数加正数没有问题,但是后面的测试出现了问题

1:怎么会有两个0呢?

  因为1000和0000都表示 零

2:怎么正数加负数会出现问题呢?

  因为符号位引起的。

总结一下:

1、原码直观

2、正数相加没问题

3、0有两种表达,运算时需要将-0转换为0,也就是1000转换为0000

 


 

四、反码

正数的反码不变。

负数的反码:符号位不变,将原码取反。

例如:

原码000的反码就是0110【计算机原理】二进制的原码、反码、补码_运算器_02

 

 

 

 

 

 

 

 

 

 

然后我们试一试用反码计算一下刚才没有解决的问题

  • 0010 + 1101 = 1111   1+(-1)=0    把1111取反码,1000,也就是说两个相反数相加取反码结果没有问题
  • 1110 + 1011 = 1001 (-6)+(-3)=(-6)取反得到1110, 这样算出来的是-6,出错了

【计算机原理】二进制的原码、反码、补码_补码_03

 

 

总结一下:

1、反码在计算相反数相加的时候不会出错(计算的时候会遇到运算位溢出,此时直接忽略高位即可)

2、0还是有两种表达0000和1111

3、容纳数字的范围和原码相同(如上图,原码与反码集合存在映射关系)

4、往往是中间变换量,不会直接用


 

五、补码

正数的补码不变。

负数的补码等于反码+1。

 

我们需要注意的是,目前大多数书籍只介绍了补码如何计算,但是都没有讲清楚为何是这样计算,以及这样计算的依据。

笔者在初学的时候也遇到了很多疑惑。关于补码的严格定义,可以自行百度,里面会介绍模与同余数的概念。

 

在此简单介绍一下,举一个生活中常见的12进制的例子来说明模的概念:

假如当前有一个时钟,指针指向9,如果我要调到12点,我们有两个方法,+3或者-9.

【计算机原理】二进制的原码、反码、补码_二进制数_04

 

 也就是说凡是-9的运算都可以看做是+3的运算。

这个情况下,模是12(mod)

 

思考到这里时请放缓脚步,慢慢思考。

我们会发现,9+3居然和9-9在某种意义上的效果是一样的。

既然两者效果相同那么一个数a减去一个数b就相当于加上这个数b的同余数。

于是推出模的一般公式:a-b=a-b+mod=a+mod-b

 

利用这个思想,我们把它带到二进制的世界里(假设是四位的二进制)

 我们试图运算0011 - 0010 = 0001,但是我们发现计算机中没有减法器,不能算。

我想便利用上面的思想,减去一个数等于加上一个数的同余数,也就是0011 加上0010的同余数即可

四位二进制的模 10000,那么0010的同余数就是10000-0010=1110,

那么我们就直接0011+1110=10001,但是我们是四位的运算,多出的一位会被直接舍弃,计算机会把多出来的一位放在psw寄存器中,不讨论。

那么至此,我们就可以利用补码计算加法和减法了。

想必你有疑问,怎么求一个数的补码呢?我们经过大量计算发现,补码竟然是原码的反码+1,非常不可思议。

为什么会这样呢?


 

六、总结与原理

因为负数的反码加上这个负数的绝对值正好等于1111,在加1,就是10000,也就是四位二进数的模,而负数的补码是它的绝对值的同余数,可以通过模减去负数的绝对值得到它的补码,所以负数的补码就是它的反码+1。

 

 

 

参考文献:Programming in C