美文网首页程序员今日看点
你所不知道的补码

你所不知道的补码

作者: 润着 | 来源:发表于2016-10-15 22:46 被阅读100次

某君不无兴奋地跟我说他有个重大发现: java里最小负整数的绝对值等于它本身! 程序员朋友可以试试以下判断:

Math.abs(int.MIN_VALUE) == int.MIN_VALUE

不管怎样, 取绝对值后一定是个正数, 怎么可能等于一个负数呢.乍一看, 太二和尚摸不着头脑. 向来以精准著称计算机世界, 怎么会得出如此可笑的结论?

其中一定有什么隐情! 凭直觉, 这应该和补码有关. 补码, 初中时代的知识, 不出意外地, 忘得差不多了, 先温故一下, 没准能知新.

正数的补码等于它自己, 负数的补码等于其反码+1.

计算机是以二进制方式表示数字的, 其中负数又以补码的方式表示. 当回忆起这点的时候, 有一个问题吸引了我:为什么负数要用补码表示呢?, 这似乎是一个和1+1为什么等于2一样傻的问题, 所以当年聪明的我没敢问老师为什么. 如今智商越发下降, 类似的问题也越来越多, 然后, 像小孩子发现更好玩的玩具一样, 开头那个问题就被晾在一边了…

大概一开始人们也没设计出补码这玩意儿, 毕竟谁会上来就找麻烦搞这么复杂的东西. 应该是很自然地第一位是符号位, 0表示正数, 1表示负数, 剩下是表示值的多少. 当然, 对于人类轻而易举想到的答案, 上帝一般是要发笑的. 这个方案会有什么问题呢? 让我们简单地假定整数是用3个比特表示的, 其表示的所有数字, 排列组合如下:

000: 0, 001: 1, 010: 2, 011: 3, 100: -0, 101: -1, 110: -2, 111: -3

这样也能work. 但很显然的不足是, 0有两种表示法, 有点浪费空间了. 还有一个更隐蔽的缺点, 用一道题来说明. 按上述规则计算下1-1, 也就是1+(-1)的结果.

001+101=110

110就是-2, 显然不对. 那么如何设计才能让同时弥补上述两个缺点呢? 这时候, 补码就隆重登场了. 按补码的规则重新穷举上述排列:

000: 0, 001: 1, 010: 2, 011: 3, 100: -4, 101: -3, 110: -2, 111: -1

0不再重复了, 表示的空间从[-3, 3], 扩大到[-4, 3]. 而且1-1的计算, 变得简单自然, 丝般顺滑(最高位溢出):

001+111=000

因此, 不必为加法和减法设计两套计算电路! 两个看似不同, 甚至对立的逻辑, 得到了统一. 设计之巧妙, 令人叹服. 看似很傻的问题, 细细研究, 原来这般微妙, 优雅得简直像艺术品, 不得不佩服提出补码那位兄台.

绕了个圈, 回到最开始的问题. 绝对值的计算大家都清楚: 正数, 直接返回它自己, 负数, 返回其相反数. 而java计算相反数, 就是取其补码. 仍然拿3比特的为例, 最小的负数是100(-4), 取反是011, 加1后是100, 还是-4. int类型一般是32比特, 但演算过程是一样的.

写代码如何能少出bug? 做架构如何能更灵活适应需求的变化? 一个共同的答案是, 发现和归纳事物的规律, 通过巧妙的设计, 或更高的抽象, 减少差异性, 提高普适性.

设计行业里流行少即是多的理念. 我想, 少不是刻意删除, 不是空洞无物. 少, 是在充分理解的前提下, 找到那个支点, 四两拨千斤, 用最小的付出, 撬动最大的收益. 九九归一, 少得下来, 一定是看透了规律, 抓住了本质.

上面对补码的理解, 足够概括和普适了吗? 并没有.

先试试在进制上做点延展. 小学生都会的减法, 能否统一成加法呢? 答案是肯定的. 事实上,

两整数 A、B 用同一个正整数 M (M 称为模)去除而余数相等,则称 A、B 对 M同余,记作: A=B (MOD M). 具有同余关系的两个数为互补关系,其中一个称为另一个的补码.

那么, 一个更加概括的理解是:减去一个数, 等于加上这个数的补码.

数学源于生活, 让我们举个日常生活的例子. 时钟连3岁小孩都能看懂, 比11点早3小时是8点, 比11点晚9小时也是8点, 嘿嘿, 说的就是这个理, 只不过这里的模是12. 而计算机用的是二进制, 以2为模: 1-1 = 1+1 = 2+0 = 0 (2被抹掉了).

所以下回教小孩子做减法可以这么说: 7-3 = 7+7 = 10+4 = 4. 当然, 要解释为什么10被任性地抹掉了, 也挺费劲.

相关文章

  • 你所不知道的补码

    某君不无兴奋地跟我说他有个重大发现: java里最小负整数的绝对值等于它本身! 程序员朋友可以试试以下判断: Ma...

  • 原码,反码,补码杂谈

    本文从原码讲起。通过简述原码,反码和补码存在的作用,加深对补码的认识。力争让你对补码的概念不再局限于:负数的补码等...

  • 关于补码_2019-03-29

    整数的补码正数的补码正数的补码等于源码负数的补码负数的补码:源码中符号位保持不变,其余各位取反后再加1 小数小数的...

  • 汇编

    补码 在求补码 得真值

  • 补码:从符号位负权理解

    我所查看的绝大多数关于补码原理的资料都是从钟表原理、模数运算之类的开始讲起,让我觉得很混淆。所以关于补码的理解我打...

  • Java中的非运算~

    涉及到的概念:原码、补码涉及到的公式: (1)正数的原码 = 补码;(2)负数的 补码 = ( 原码 - 1 )再...

  • 数值是以补码表示的

    正数的补码与原补码相同 负数的补码:将该数的绝对值的二进制数按位取反后再加1 例如:求-10的补码 10的原码: ...

  • 原码、反码、补码和移码

    书中关于原码、反码、补码和移码的定义如下(n是机器字长):原码: 反码: 补码: 移码: 原码, 反码, 补码的基...

  • 2018-10-22 Python31 原码、反码、补码

    原码、反码、补码 1)如何计算补码?规则: 正数:原码 = 反码 = 补码负数:反码 = 符号位不变,其他位取反补...

  • int数字的表示

    在计算机中int型数字使用补码的形式在存储。首先说明补码的计算方式。正数和零的补码就是他们本身。负数的补码是符号位...

网友评论

    本文标题:你所不知道的补码

    本文链接:https://www.haomeiwen.com/subject/nfsoyttx.html