关于原码,反码,补码的一点注记

整数在计算机中是通过二进制的比特串来存储的。
将整数编码成二进制比特表示有几种方法,即通常所说的原码,反码补码

比如我们用4位模式xxxx,其中x {0,1} 来存储一个整数,那么第一位是被预留表示整数的符号的,0代表正数,而1代表负数。比如-3就是1011;2就是0010
除了这个第一位的表示,剩余的位就是正常的二进制翻译,这种表示称之为原码

原码的一个缺点在于计算的时候会出现问题,特别是整数的减法。最简单的比如 01 ,如果用原码表示,直觉上似乎是0000-0001=1111,这样转化成原码就是0-1=-7了,显然不正确;或者我们不知道应该怎么算。再比如1+(-1)=0001+1001=1010=-2?所以,原码的计算是有问题的。

事实上,在计算机之中,我们不需要考虑减法,而只考虑加法,当两个数相减的时候,我们考虑负数。另一方面,这样做需要配合上补码的表示,便可以形成完美的无差错运算体系。那么,究竟什么是补码?

一般地,对于一个整数z,它的补码有两种人工的求法,当然他们的结果是一样的。如果它是正数,则其补码就等于它的原码;如果它是负数,那么它的补码是这样定义的,将其绝对值对应的原码(即-x的原码)的位模式从最右数起,碰见的第一个1不动,而将这个1左边的位模式全部取反(即0变成1,1变成0)。如图1.

图1

另一种方法,就是通过反码。简单来说,所谓反码就是按位取反。对于正整数,反码和原码一样,而对于负数,它的反码等于将原码除符号位以外的位全部取反。这样,第二种求补码的方式就是,正整数和原码一样,而负整数而言,是将它的反码+1(即通常的二进制加1)。

最自然的问题,就是为什么这样定义?这样定义为什么合理?并且使之恰好成为完美的运算体系?

首先我们注意到,一套位模式(简单起见我们考虑短的位模式作分析,长度不是本质的问题,对于长的模式也是一样的道理),比如说4位xxxx,那么它所能表示的整数有一个范围。当第一位由于计算机的原因必须用来表示符号以外,这个位模式能表示的最大正数显然是0111,也就是7. 那负数最小应该是1111,也就是-7(如图2). 这样的表示方式有一个天然的缺陷,即1000没法表示任何东西,因为-0显然没有必要。我们先不管这个问题,先看一个更重要的问题,就是在计算机之中正常的加法也“不正常”,也就是所谓的溢出。当我们仅仅能用4位模式(或者一般地,计算机中就是有限位模式,不论多大都是有限)来存储数据的时候,我们的存储范围是有限的,即我们不可能存储所有的整数。因此加法的封闭性是无法保证的。(而也是没有必要保证的,因为我们采用的是正常的整数加法,溢出了就是工程上需要考虑的问题。另外,如果要保证加法的封闭性,我们对于这个有限集合上的加法就需要重新定义了,即通过“模加法”,它其实也可以通过同态来得到。但是这样就不是正常的加法运算了,而我们在求两个整数加法的时候是要常规的加。)

图2

这个时候,我们需要确定这个有限集中的每个元素对应的位模式表示。我们要做的,是要使得位模式表示既能够一一对应这个范围内的整数,又保持运算。从代数上说,这差一点就是就是同态。之所以说差一点,是因为溢出的存在,使得这两个集合的加法运算都不是封闭的。

于是我们考虑更一般的情形,所有的整数集合 Z 和它的二进制表达 B 之间是一一对应的(记为 f ),或者更进一步说,他们是加法同构的(一定要注意,这个时候,对于一个负整数-y,它被这个同构对应到一个-xx..x,后面的xx…x是y的二进制表示)。当我们采用计算机的存储模式,即有限位位模式的二进制存储(首位作为符号位),不妨说是n位比特串。记m=2n Bm 为所有n位2进制元素组成的集合。那么显然 B Bm 之间有一个同态,并且它是一个满同态,我们记为 g . 于是我们显然得到一个交换图,也就是Z Bm 的同态 gf (图3)。

图3

这个同态就是补码的编码方式。事实上, f 是直接的,正数就是二进制表示,负数就是绝对值的二进制表示前面加个负号。然后,对于g,我们必须把零元映到零元;为了让第一位表示符号位,我们充分利用剩余的位,即第一位为0的元素就是它的二进制表示。因此只需要再确定逆元即可,从而我们将-xx…x的负数,对应到它的绝对值xx…x所对应的 Bm 中元素的逆元。举例来说,4位模式, n=4,m=24=16 . 则0111是对应最大的正数0111,那么-0111就对应于它在 B16 中的逆元1001,也就是4位模式中那个和0111相加等于10000的元素。要注意,在 B16 中10000就是0000,即零元。其他以此类推。最后,我们考虑多出来的1000,它要么对应1000要么对应-1000,这两者其实都是可以,但是为了与计算机的要求一致,它应该表示一个负数,所以对应-1000.

我们说明两点事情。第一, Bm 就是计算机当 n 位存储模式下的计算方式,它是封闭的,并且它是一个加法群。第二,我们的目标是考虑Z的一个子集它的二进制表达在计算机中的合理编码及运算。通过上面这个复合同态 gf ,我们就已经得到了 {7,6,,6,7} 的二进制表达,并且在不溢出的情况下,它是完美的计算体系。事实上,我们会发现问题麻烦的地方只在一正一负相加的情形,而我们的对应只需要将绝对值较大的那个数分成较小的那个数的逆加上另外一个数,然后由于一个数加它的逆刚好为零,所以抵消了那一部分,也就得出正确的结果。比如5-3=0101+(-0011)=0101+1101=(0010+0011)+1101=0010+(0011+1101)=0010+0000=0010.

最后,我们从上面的复合同态的定义方式可以知道补码的人工计算方式。我们需要强调,我们应该这样来看问题,即补码不是从原码来的,补码是一种映射或者说编码方式,它是一种有自己理论依据的完善的计算机处理整数的编码方式,是一个独立的体系。而原码是更接近人类理解的计算机的另一种整数存储方式。所以我们所谓的从原码求补码,是试图找这两个编码之间的关系(图4)。

图4

我们最后说明为什么从原码求补码的方式是这样的,或者说我们解释为什么补码是如我们一开始定义的那样的。这其实很简单,我们只需要分析这个复合同态,结合 B 到原码的一一映射就可以知道。事实上,对于正数(我们指原码),我们看到,它的原码和补码是一样的;而对于负数1xx…x(除了100…0以外,这个数是补码仅有的,原码不会有这个数),我们看到,我们先求它的绝对值,即将符号位变为0,得到0xx…x. 然后再求这个绝对值映射到 Bm 之后(也就是样子完全没变)在 Bm 之中的逆元。而逆元就是和它相加等于00…0的位模式。要和0xx…x相加等于00…0,那显然就是考虑0xx…x从右数起的第一个1不动,其余左边的全部取反;或者说,这个逆元就是1xx…x最右边的1和符号位的1不动,两个1之间的数全部取反得到的。这就是这个原码的补码表示。

参考文献:
J.Brookshear,《计算机科学概论(第11版)》,人民邮电出版社。

Stkcd [股票代码] ShortName [股票简称] Accper [统计截止日期] Typrep [报表类型编码] Indcd [行业代码] Indnme [行业名称] Source [公告来源] F060101B [净利润现金净含量] F060101C [净利润现金净含量TTM] F060201B [营业收入现金含量] F060201C [营业收入现金含量TTM] F060301B [营业收入现金净含量] F060301C [营业收入现金净含量TTM] F060401B [营业利润现金净含量] F060401C [营业利润现金净含量TTM] F060901B [筹资活动债权人现金净流量] F060901C [筹资活动债权人现金净流量TTM] F061001B [筹资活动股东现金净流量] F061001C [筹资活动股东现金净流量TTM] F061201B [折旧摊销] F061201C [折旧摊销TTM] F061301B [公司现金流1] F061302B [公司现金流2] F061301C [公司现金流TTM1] F061302C [公司现金流TTM2] F061401B [股权现金流1] F061402B [股权现金流2] F061401C [股权现金流TTM1] F061402C [股权现金流TTM2] F061501B [公司自由现金流(原有)] F061601B [股权自由现金流(原有)] F061701B [全部现金回收率] F061801B [营运指数] F061901B [资本支出与折旧摊销比] F062001B [现金适合比率] F062101B [现金再投资比率] F062201B [现金满足投资比率] F062301B [股权自由现金流] F062401B [企业自由现金流] Indcd1 [行业代码1] Indnme1 [行业名称1] 季度数据,所有沪深北上市公司的 分别包含excel、dta数据文件格式及其说明,便于不同软件工具对数据的分析应用 数据来源:基于上市公司年报及公告数据整理,或相关证券交易所、各部委、省、市数据 数据范围:基于沪深北证上市公司 A股(主板、中小企业板、创业板、科创板等)数据整理计算
首先,我们需要了解如何将十进制转换成二进制原码反码补码。 1. **原码**:正数直接表示,负数则最高位为1(对于有符号整数)。 - **95 (十进制)**: 原码 = 000001010101(因为95在8位内,不足8位补0) - **-131 (十进制)**: 原码 = 111110100011 (负数最高位为1) 2. **反码**:对原码取反,然后加1(对于有符号整数)。负数的反码是除符号位外全变1。 - **95 (十进制)**: 反码 = 111110101010 (+95的反码) - **-131 (十进制)**: 反码 = 000001011100 (-131的反码) 3. **补码**:也是对原码取反,然后加1,但对于负数,有一个特殊情况:零的补码等于其本身。 - **95 (十进制)**: 补码 = 111110101010 (+95的补码,无需调整) - **-131 (十进制)**: 补码 = 000001011101 (-131的补码,注意最后一位由1变为0) 4. **浮点数的原码反码补码**: - **0.125 (十进制)**: 由于是小数,通常会采用偏移二进制表示法,即在最高位后面跟上实际值的二进制。0.125 = 1 / 8 = 0.00011001... - 原码 = 000000000000011001000... (保留足够位数) - 反码 = 11111111111110011111100... (先取反再加1) - 补码 = 11111111111110011111100... (小数部分不变,不需要加1) - **-0.875 (十进制)**: 同样是小数,可以将其转化为二进制形式 -0.125 * 8 = -1 = -1000... - 原码 = 100000000000001110000... (带符号,注意最左一位) - 反码 = 01111111111111000111100... (先取反再加1) - 补码 = 01111111111111000111100... (小数部分不变,不需要加1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值