原码、补码、反码扫盲
很多学习编程的童鞋,一定会在入门的时候听说原码、补码、反码之类的东西吧。但是我发现大多数童鞋还是不知道这些东西到底是用来干嘛的,总以为是冯·诺依曼之辈在那里瞎折腾。其实不然,这些东西还是大有用处的。
本文介绍原码、补码、反码的相关知识,至少能够让你了解这些晦涩的东西存在的意义。
如果是高手,请跳过本文。
怎样表示整型数据
计算机中大量地运用着整型数据。整型数据在数学上的意义就是整数,当然这个整数可正可负。以下,我假定你有二进制和十进制互相转换的能力。计算机中数据是以二进制的形式存储的,通常你学过的十进制转换成二进制都是在非负整数的情况下,但是如果我让你转换一个负的十进制数呢?聪明的你也许会在前面加上一个负号,没错,数学上可以这样干。计算机呢?
也许聪明的你会想,那我在计算机有符号的整型数据中保留一位,当它是 0 的时候表示这个整型是正的,当它是 1 的时候表示这个整型是负的,其余二进制位数则按照普通的二进制转换十进制这样来计算。没错,这样是可以唯一地表示每一个(范围内的)整数的,但是,这样会遇到一个问题。
会遇到什么问题
当我们在做减法运算,或者加上一个负数的时候,我们就需要讨论这两个整型的正负了。我们以一个正数减去另一个正数(不妨记为 a – b)为例,首先我们需要比较两个数 a, b 的大小,如果 a 比 b 大,那么我们得到一个正数;如果 b 比 a 大,那么我们把 a, b 调换后,作减法,再加上一个负号(即将那个表示符号的二进制位记为 1)。
当然还有其它的运算情况,这样讨论的种类数就多了;甚至两个数中可能有正又有负,这样问题就显得更复杂。并且,这会极大地降低程序的运行效率。
难道不能只用一种方法就解决所有的负数运算问题吗?
方法是不会变的
没错,方法还是原来计算正数之间二进制加减法的方法。改变的仅仅是表示负数的形式。这也是补码、反码存在的意义。
如果你是 C++ 程序员,那么你应该会知道,一个 32 位有符号整型数据,最高可达 2147483647 . 那么你可能试过,在 C++ 中,这个数加 1 就变成了 -2147483648 了。这俗称溢出。与其它语言不同的是,C++ 是不会检查这类溢出的,所以以 C++ 举例有助于探寻整型数据的表示方法。(当然,这里的 C++ 包括 C 等.)
实际上,2147483647 在计算机中的二进制表示为:
0111 1111 1111 1111 1111 1111 1111 1111
这个二进制数加 1, 就成了:
1000 0000 0000 0000 0000 0000 0000 0000
没错,上面这个数就是 -2147483648 的表示方法。你也许会很纳闷,因为上面这个数按照老师教你的方法计算,应该是 2147483648 才对。但是我们有一个前提,这是一个有符号的整型。那这个计算机是怎么回事呢?
我们试探性地将 2147483647 和 -2147483648 相加,数学上知道它是 -1. 计算机中得到的结果,就是:
1111 1111 1111 1111 1111 1111 1111 1111
如果你有编程经验,或者经常执行 memset 或者 fillchar 之类的函数,你会发现这个东西其实就是 -1. 为什么它是 -1 呢?
我们不妨取其反码,然后取其补码,你得到的,就是:
0000 0000 0000 0000 0000 0000 0000 0001
啊!这不就是 1 吗?我们尝试取 -2147483648 的反码的补码,得到的是:
1000 0000 0000 0000 0000 0000 0000 0000
其实这刚好就是 2147483648. 这个数比较特殊,因为它的反码的补码和原码是相同的。
也许你已经找到规律了,当有符号的整型第一个二进制位是 0 的时候,这个有符号整型是正数,并且其值就是整个二进制数表示的十进制数;当有符号的整型第一个二进制位是 1 的时候,这个有符号整型是负数,并且其值是整个二进制数的反码的补码表示的十进制数。
这样表示的作用是什么
这样表示的作用上面其实已经暗示了,就是使用普通的四则运算法则就可以不加讨论地直接进行正数和负数之间的运算。举个例子,比如 0 – 1 = -1, 那么我们可以按照普通方法计算(在不够减的时候可以向前“借”一位):
(1)0000 0000 0000 0000 0000 0000 0000 0000
- 0000 0000 0000 0000 0000 0000 0000 0001
================================================
1111 1111 1111 1111 1111 1111 1111 1111结果就是 -1. 你可以任意测试这个方法的正确性,总之,你应该没见过电脑算错这些吧?电脑就是这样算的。
怎样输出负数
计算机在运算的过程中是不会关心整型数据是正是负的。但是,使用者一定会关心。所以计算机输出的时候才会判断是正数还是负数。当第一个二进制位是 0 的时候,直接输出正数;当第一个二进制位是 1 的时候,输出负号,再输出这个二进制数的反码的补码。问题迎刃而解。

好文章,沙发…
嘿嘿。
专门写给你的。
哟 一看就知道是你写的
是我写的,但是为什么一看就知道呢?
59君了来了…
我记得好像你要拜他为师的。