二进制的补码

在计算机中 数字都是以二进制形式保存的(以8位为例 之后的也是) 比如要保存1那么在计算机中是以00000001的形式保存的 那如果是-1呢?

事实上-1是以11111111的形式保存的

数字是有正负之分的 对于计算机也是同理 对于一个数而言 在平时我们表示数字的时候要表示正的100直接写100或者+100就行了 而负数则-100就行了 通过+/-来区分是正数还是负数 同理 计算机也需要一个标志来标识这个数是正数还是负数 而通常用 最高位来表示 0表示正数 1表示负数 如:1则表示成0.0000001 -1则表示成1.0000001 由于最高位留了出来表示正负号 所以能表示数据的有效位数只有7位了

但是这里你看到 我两次表示-1的写法似乎有点不一样 最开始的那个是不是写错了啊 其实没有 最开始的那个是-1的补码形式 而计算机也通常使用补码来表示数字的 而下面的是原码形式 原码形式说直白一点就是平常的二进制表示方式 前面多了一个01表示正负而已

对于补码 百度百科里面有个不错的例子

假设现在时钟是3点整如果此时真正的时间是1点整 那么你想要把时间调整正确 你有两个做法

  1. 把时间倒拨2小时(-2)
  2. 把事件顺拨9小时(+10)
通过上面两个任意一个步骤你可以把时间调整正确 也是就说可以看出实际上 减去2个小时和加上10个小时 并没有什么影响 所以:
当前时间 - 2 = 当前时间 + 10
理论上来说 要是这样的话 他们会相差12个小时 但是在时钟上无论你顺时针向前拨动多少个小时 一旦超过12点它又会从从1点开始 就算你拨上个几百圈 他的时间范围也不会多一个13出来 逆时针同理

其实计算机也是这个概念 为什么?先还是用时钟举例子 在时钟上如果12点整加上1个小时?没错他不会变成13点整而是又从1开始了(我没说电子表啊)

现设现在抛开一切不管 如果一个二进制 11111111+1 会得到什么样子的结果? 没错是 100000000(共9位) 但是不要忘了由于只有8位给你用 这里的结果已经多出一位来了 所以最前面的那个1会被计算机抛弃掉 也就是溢出 所以你的结果不是100000000而是00000000 和时钟一个原理有回到原点了

刚才上面说了 对于时钟而言 减去n个小时 等同于加上(12-n)个小时 那么这个(12-n)就相当于一个补数 这样的话所有的回拨动作都可以用顺拨动作来代替 同理 那么计算机在做减法运算的时候也可以等同于加上一个对应的补数 这样计算机就只需要知道加法运算的规则就可以了而不必知道减法的 所以对于计算机来说 减去一个数就等同于加上他的补数也就是补码 而这里我们所要求的就是这个补数(补码)

从上面的时钟可以看到要减去n个要是等于加上(12-n) 而这个12是时钟能表示的最大值 超过这个值就又回到原点了 所以用他减去n得到的就是n对于12的补数

计算机中你也可以这样去求出补数 用能表示的最大值减去n得到的就是他的补数了 比如现在要计算:5-1 那么

0.0000101-0.0000001
=
0.0000101+1.0000001  //5-2=5+(-2) 最高位1表示负数
0.0000101+? //当让不会是像上面一行的那样计算 不是说了吗 这里是需要加上-2的补码
那么那个'?'是多少 最开始上面的时钟是最大值减去相应的数就行了 这里也可以这样干 如-1的补码:
  1111111   //7位能表示的最大值
- 0000001   //相应的数
= 1111110   //对这个结果加1
= 1111111   
为什么要加上一个1?时钟是12点过后又重新从1点开始 而计算机里面溢出了可不是从1开始的而是从0开始然后才是1、2、3、...所以要多加上一个数 所以公式就变成了(能表示的最大数 - n + 1)

所以5-2中的'?'就是

  1111111
- 0000010
= 1111101   //+1
= 1111110
那么5-2就等于:
0.0000101-0.0000001
=
0.0000101+1.0000001  //5-2=5+(-2) 最高位1表示负数
0.0000101+1.1111110  //-2的补码
=>
  0.0000101
+ 1.1111110
=10.0000011   //溢出的1抛弃
= 0.0000011   //=3
不要被那个点迷惑了 那个点 只是用来表示与最高位做间隔的的实际上那个点是不存在的

在上面可以看到 一个减法运算被变成了一个加法运算 而里面11111110就是-2对应的正数的二进制形0.0000010式的补码

在计算机中一个数通常都是用补码来表示的 而一个正数的补码就是他本身而负数的补码 则可以安上面的方式计算 不过很明显上面的计算方式就是 其实仔细观察其实就是将原本的取反加1 为什么?看看过程 先做减法过程 然后加一  做减法的时候 上面一排是不是全部都是1?而1减去下面对应位数上的数 如果是1结果必然是0(1-1=0) 如果是0结果必然为1(1-0=1)是不是就是在取反的过程? 所以求补码的过程就是:

将其正数的二进制原码形式的每一位取反+1
综上可以看出 1字节(8位)所表示的数是有范围限制的 如果忽略最高位表示一个无符号数(没有符号位也就是全部是正数)那么他的范围是0-255 如果要表示有符号(最高位表示符号位)那么他的范围是多少?

能表示的最大数是毫无疑问的肯定是:0.1111111 这个值是127

先不考虑补码问题 要是用源码表示 你会不会以为最小的数就是:1.1111111(补码:1.0000001) -127?也就是刚好对称过来

事实上我不会告诉你 其实能表示的最小数是-128  啥?-128?1.100000000(共9位 原码)?、、、是的没错 能表示的最小的的确是-128 考虑问题的时候 永远不要忘了那个最可爱的0

通常情况下你可能会这样认为有多少个正数就会有多少个负数啊比如+1(-1)、+2(-2)、+3(-3)、...能表示的最大数是+127那么能表示的最小的也自然是-127啊...+1(-1)什么的 你当两个值也罢 但是+0(-0)你也把他们当作两个值么?没区别他们都一样0、、所以为了不浪费 -0(1.0000000 原码) 这个特殊的东西 直接用来当作-128的补玛形式 所以说位数相同的情况下 二进制能表示的负数总是比正数多一个

所以说在编程的时候那些什么int short什么的 能表示的负数都会比正数多一个 而且他们的表示范围也是有限的 通常情况下在编程的时候一个int四个字节也就是32位 最高位符号位表示数据的有效位有31位 当然如果你觉得你这个变量压根就不会用来表示负数 你可以直接声明成无符号int也就是最高位不表示符号那么他能表示的数据范围则就更大了 不过只能是正数

对于二进制的补码这里就说这么多 注意计算机中二进制有三种形式 原码 补码 反码 不过重点还是补码 因为计算机中 通常表示数字的时候都是用的补码表示

比如在C#中:

用二进制方式转换成字符串 之所以看到那么多1 是应为a是int类型四个字节32位

或者 在windows的计算器上你也可以看到:

上面有-1的二进制表示形式 都是用补码的形式表示的 - -!、这里之所以看到8个1是因为左边下面我选的是字节类型、、一字节8位、、

对于补码 这就讲这么多、、、


添加时间:2014-04-09 03:50:20 编辑时间:2016-10-23 17:58:11 阅读:1175 
计算机的一些知识 
还没有人留言 要不你来抢一个沙发?
  • 编写评论

      我觉得区分大小写是一个码农的基本素质
[访问统计] 今天:21 总数:155075 提示:未成年人 请在大人陪同下浏览本站内容 还有:世界上最帅的码农 -> 石头 RSS:http://st233.com/rss Powered by -> Crystal_lz