二进制补码的数学原理

博客地址:https://www.cnblogs.com/jackieL/算法

做者: 梁言  spa

时间:2019年2月19日指针

最近在网上查了不少关于补码的文章,要么是长篇大论,要么就是错误百出,因此我用简单的语言把这个问题分析一遍,以便于你们理解记忆,若有错误欢迎留言指正。blog

 

一,“原码”、“反码”、“补码”的基本概念同步

针对还不明白这几个基础概念的同窗们须要阐述一下,若是已经知道的同窗自行跳过。博客

一、“原码”数学

就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其他位数表示数字的值。it

如:十进制  6 = 二进制原码 0000 0110 基础

  十进制 -6 = 二进制原码 1000 0110循环

二、“反码”

正数的反码与其原码相同,负数的反码是对其原码逐位取反,符号位除外。

 如:十进制 6 = 二进制原码 0000 0110 = 二进制反码 0000 0110

   十进制 -6 = 二进制原码 1000 0110 = 二进制反码 1111 1001

三、“补码”

正数的补码与原码相同,负数的补码是在其反码的末位加1。

如:十进制 6 = 二进制原码 0000 0110 = 二进制反码 0000 0110 = 二进制补码 0000 0110

  十进制 -6 = 二进制原码 1000 0110 = 二进制反码 1111 1001 = 二进制补码 1111 1010

 

2、“原、反、补”的产生缘由

由于计算机cpu只有加法运算器,没有减法运算器,因此须要把减法转换为加法来作,因此天然就产生了“原、反、补”来将减法转换为加法计算。

虽然这个东西有点反人类,但毕竟是机器去使用它,咱们只须要明白就行。

 

3、“反码”应运而生

 

二进制“反码”很容易产生,由于cpu有一个二进制取反逻辑门电路,只要把“原码”经过那个“门”出来就变成“反码”了

“原码”与“反码”有一个特色:

以一个字节二进制数据为例

十进制 -6 = 二进制原码 1000 0110 = 二进制反码 1111 1001

任意一个数的“原码”加上这个数的“反码”=> 10000 0110 + 1111 1001 = 0111 1111 结果是同样的十进制127

=> "原码"  +  “反码” = 127

=> "原码" = 127 -  “反码”

z 为一字节二进制正数(就是须要咱们减去的数值),等式两边同时减去z

=>"原码" - z = 127 -  “反码” - z 

=>("原码" - z) = 127 -  (“反码” + z) 

由于 "原码" = 127 -  “反码”

因此(“反码” + z) 为("原码" - z)的“新反码

反之("原码" - z)(“反码” + z)的“新原码

这样就把减法转换为了加法。

若是没有看懂同窗没关系,上图=====>

4、”补码“补漏洞

须要注意的是,当(“反码” + z)的值大于等于127时,计算结果就会出现错误

例如:十进制 8 = 二进制反码 0000 1000

   十进制 6 = 二进制反码 0000 0110

   十进制 -6 = 二进制原码 1000 0110 = 二进制反码 1111 1001

   6 + (- 6) => (反码)0000 0110 + (反码)1111 1001 = (反码)1111 1111 =>(原码)1000 0000 结果为-0,负0在数学上是无定义的

     8 + (-6) => (反码)0000 1000 + (反码)1111 1001 = (反码)0000 0001 =>(原码)0000 0001结果为1,明明8-6结果为2啊,又出错了

    (-6) + (-6) => (反码)1111 1001 + (反码)1111 1001 = (反码)1111 1010 =>(原码)1000 0101结果为-13,明明-6-6结果-12,又出错了

错误是如何产生的了?

由于一个字节二进制的 0000 0000 有8个bit

这个二进制数字的排列数就有2^8个,结果就是256个排列数,256除以2等于128,就是有128种排列用于表示负数,128种排列来表示正数,

(如上图)原反码的圆盘只有127个指针数,跟一字节二进制自然的排列数128周期相比就少一个指针数

这样就致使“原、反码”算法的循环周期和二进制天然的循环周期不一致,不一样步而产生错误。

 

 引入”补码“

求 "原码" + ”补码“?

由于”补码“ = ”反码“ + 1 

=>   "原码" + ”补码“ = "原码" + ”反码“ + 1 

由于 "原码" + ”反码“ = 127

=>  "原码" + ”反码“ + 1 = 127 + 1 = 128 

=> "原码" + ”补码“ = 128

=> "原码"  = 128 -  ”补码“

设 为一字节二进制数(就是须要咱们减去的数值),等式两边同时减去z

=> "原码"  - z = 128 -  ”补码“ - z

=> ("原码"  - z) = 128 - (”补码“ + z)

同理(”补码“ + z)是("原码"  - z)的新补码。

这样咱们就至关于把圆盘刻度增长一位值(见下图)。

 

这样算法周期和二进制排列数周期就相匹配了。

须要注意的是:

二进制128个排列是用来表示-128到-1的

二进制128个排列是用来表示0到127的

因此一字节二进制能表示带符号数的范围是-128到127.

规定-128 用 1000 0000(补码) 表示,这个二进制很特殊它减1的效果和它取反的值同样,因此它的原码和补码相等。

-1用 1111 1111(补码)表示。

相关文章
相关标签/搜索