自学内容网 自学内容网

原码、补码、反码、移码是什么?

计算机很多术语翻译成中文之后,不知道是译者出于什么目的,往往将其翻译成一个很难懂的名词。

奇怪的数学定义

下面是关于原码的“吐槽”,可以当作扩展。你可以不看,直接去下一章,没有任何影响。
原码的吐槽放在前面是防止读者看完原码,然后看半天才看到补码,影响阅读体验。

某些书描述“原码”的时候很“奇怪”,你可能在某些书上见到过下面这样很难理解的描述(下图截自原码 - 维基百科):
请添加图片描述

这玩意是数论里的等价类或者群论里的空间的表达方式,也就是计算机里常出现的“模运算”。或者还有个更高级的名字:散列(因为很多散列算法就是模运算,然后用的等价类的思想)。

等价类:3 mod 21 mod 2的结果都为1,所以都等于[1],也就是31都是关系mod 21等价类。

那上面的那一堆是什么意思呢?

以整数原码为例,X是一个数,范围不定。

[+1011]的意思是和+1011等价的所有数:
X m o d 2 n = 1011 X mod 2^n = 1011 Xmod2n=1011

比如 n > 4 n>4 n>4的时候 2 n > 0 b 1111 2^n>0b1111 2n>0b1111
1011 m o d 2 n = 1011 ( 2 n + 1011 ) m o d 2 n = 1011 1011 mod 2^n = 1011\\ (2^n + 1011) mod 2^n = 1011 1011mod2n=1011(2n+1011)mod2n=1011

[-1011]的意思是和(2^{n-1} - 1011)等价的所有类:

( 2 n − 1 − X ) m o d 2 n = 1011 (2^{n-1} - X) mod 2^n = 1011 (2n1X)mod2n=1011

比如是 8 位的数字:
( 2 8 − 1 − ( − 1011 ) ) m o d 2 n = ( 10000000 + 1011 ) ) m o d 11111111 = 10001011 (2^{8-1} - (-1011)) mod 2^n =\\ (10000000 + 1011)) mod 11111111 = 10001011 (281(1011))mod2n=(10000000+1011))mod11111111=10001011

这是教材,不是论文,而且一般论文也不用这么说吧?

这种表达方式唯一的好处就是让你理解溢出之后该怎么处理,因为取模运算的值就是溢出后得到的值。

说实话这种表达方式就不应该出现在任何现代教材中,哪怕是很多数学分析的书都不会这样描述数的。我不知道这种用法最早出现在哪里,但是欧美一些常见的计算机组成与设计教材中没有出现过这种用法,也就是说并不是盲目学来的。

不论是“true code”还是“true form”都在英文搜索中难以找到。WiKi “有符号数处理”中,“原码”对应的是“符号及值(sign & magnitude)”,英文版直接就是“Sign–magnitude”。这玩意的在一些教材中的翻译是“符号和幅值表达法”,看看这个名字多清晰和直白。

这个方法读者理解就好,没必要学,后文也完全不使用这个方法,怎么容易理解怎么来。但计算机科学确实有很多算法使用了等价类的概念,所以如果你要走算法方向,还是要看看的。

原码

原码就是我们常用的数,在计算机中就是用二进制表示的十进制数,不论正负、不论整数还是小数。

n位原码就是用最高位(小端就是最右位)当作符号位(0为正数,1为负数),关于0对称范围内的数( − 2 n ~ 2 n -2^n~2^n 2n2n),比如-4~4-16~16,范围的两个端点关于0对称,正负数的个数相同。

补码(2’s complement)

n位补码就是用最高位(小端就是最右位)当作符号位(0为正数,1为负数)关于0不对称范围内的数( − 2 n − 1 ~ ( 2 n − 1 − 1 ) -2^{n-1}~(2^{n-1}-1) 2n1(2n11)),比如-16~15,范围的两个端点关于0不对称。

这里概念很容易和和其他码搞混,比如原码。

但其实只用记住一个关键点:补码的-11111,而原码是1001

换言之,从零值的“生长”来说:

  • 原码相当于少一位(最大的那位)的无符号数。抛开符号位-xx的表达是一样的,所以上下限的绝对值是一样的。
  • 补码从0开始增减,0b0000-1,借位算出是0b1111。但是+1增的时候,要注意不能让最大位为1,所以上限比下限绝对值少1

补码是现在主流的格式,所以各种考试也主要考补码。所以只讲一下补码的计算。

补码计算的时候,加减法要带着符号位进行,乘除法就是左移补0,右移补符号位

比如:

  • 1011*2,得到的是0110
  • 1011/2,得到的是1101
  • 0011+0011,也就是3+3=6=0110
 0011
+0011
-------
 0110
  • 0011-0111,也就是3-7=-4=1100
 0011
-0111
-------
 1100

用加减法可以很容易得到-x对应的二进制,反之亦然。

举个例子,我要计算出1111 0100的的十进制,那么可以先计算出和0(0000 0000)的差(前 4 位相同,甚至可以不用写):

 0000 0000
-1111 0100
-----------
 0000 1100

得到12,加上符号-(原二进制符号位为1,也就是负的),那么最后得到-12

反之,我们想计算出-8的二进制,也就是和08(0000 1000),那么就可以:

 0000 0000
-0000 1000
-----------
 1111 1000

是不是很简单。

反码(1’s complement)

反码中,一个数的相反数就是按位取反,1001,这也是名字的由来。

比如1(00000001)按位取反,得到-1(11111110)。

所以反码和原码一样,是关于0对称的,所以正负数的个数相同。但是不同之处在于:反码有两个0,正0(0000)和负0(1111)。

在无符号数的反码中,x按位取反为 2 n − 1 − x 2^n-1-x 2n1x

因为无符号反码增长就是从0一直加,所以最大值是 2 n − 1 2^n-1 2n1。而按位取反就相当于从尾部往前倒。

你可以观察一下下面这个表格,再看看我的说法,你就会理解了。
请添加图片描述

反码(1’s complement)早期设备用的多,现在用补码(2’s complement)是主流,因为反码计算的时候更麻烦一些,只是在计算一些科学计算的时候更有优势罢了。

看开头的数字也可以看出顺序来(啊对,这两个英文中的数字就是版本,这你能想到哈哈哈哈)。

移码(Offset binary)

移码又称“偏移表示法”,这个方法现在是上面浮点数用的多,比如 IEEE 754。

移码从0000开始递增,依旧使用最高位位符号为,只不过这里1表示正数
0表示负数。与前面的几种方法相反。

有符号移码最小的负数是0000,最大的整数是111101000

这里可能好奇名字中“偏移”的意思,其实就是“给数加上一个偏移数后,使其具有非负的表达形式”。

比如上面的0,加上一个偏移1000,得到的就是1000,也就是0,非负。

关于这部分,浮点数中再细说吧。

希望能帮到有需要的人~

参考资料

《Computer Organization and Design MIPS Edition: The Hardware/Software Interface Fifth Edition》:如果你要学习计算机结构的话,这本书要比国内的很多教材好,但是翻译的确实不太行。

原码 - 维基百科

Signed number representations - 维基百科


原文地址:https://blog.csdn.net/qq_33919450/article/details/140502460

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!