计算机系统学习
今天学习了对二进制整数的位进行拓展和截断表示。
拓展数字
假如我们将一个短整型的变量转换为整型变量,由两个字节扩充为四个字节,这时就涉及到了位的扩展。
在进行位的扩展时,最容易想到的就是在高位全部补0,也就是将原来的二进制序列前面加入若干个0,也称为零扩展。还有一种方式比较特别,是符号扩展,也就是针对有符号数的方式,它是直接扩展符号位,也就是将二进制序列的前面加入若干个最高位。
对于零扩展来说,很明显扩展之后的值与原来的值是相等的,而对于符号扩展来说,则是一样,只不过没有零扩展来的直接。我们在计算补码时有一个比较简单的办法,就是符号位若为0,则与无符号是类似的。若符号位为1,也就是负数时,可以将其余位取反最终再加1即可。因此当我们对一个有符号的负数进行符号扩展时,前面加入若干个1,在取反之后都为0,因此依旧会保持原有的数值。
总之,在对位进行扩展时,是不会改变原有数值的。
在书中对于负数的符号扩展还给出了这一过程的证明,这个证明使用了数学归纳法,具体过程如下。
![](https://tva1.sinaimg.cn/large/007rAy9hgy1g2rpns18k4j30gh08iglv.jpg)
2的幂函数有一个特殊的属性,就是2^w-2^(w-1)=2^(w-1).因此加上一个权值为-2^w的位,和一个将权值为-2^(w-1)的位转为权值为2^(w-1)的位,这两项综合起来得到的结果是一样的。
截断数字
截断与扩展相反,它是将一个多位二进制序列截断至较少的位数,也就是与扩展是相反的过程。
观察书中给的例子,我们可以发现截断可能会导致数据的失真。对于无符号编码来说,截断后就是剩余位数的无符号编码数值。在书中给出了这一简单过程的证明,它主要是想表明截断前与截断后的数值的关系是取余数所得到的。而对于有符号数来说,就是在截断无符号数的基础上加上一步,做一个无符号数转补码的操作。总的来说,无符号数的截断结果是
![](https://tva1.sinaimg.cn/large/007rAy9hgy1g2rpzcjdebj30gi014jra.jpg)
而补码数字的截断结果是
![](https://tva1.sinaimg.cn/large/007rAy9hgy1g2rq05yaqtj30gs01eq2v.jpg)
我在做习题2.24时卡了好久,自己做的结果和答案就是对不上,后来才发现题目要求将4位截断位3位,我一直以为是2位,做了半天好心酸。比如对于-1来说,二进制补码表示为1111,首先按截断的位数取余得到无符号数111,再将无符号数转为补码,按照昨天的公式得到7-8=-1.
关于有无符号数转换的思考
从上面的分析不难看出,具有有符号和无符号数的语言,在相互转换时可能会因此引起一些不必要的麻烦。而且无符号数除了能表示的最大值更大以外,似乎并没有太大的好处,因此有很多语言是不支持无符号数的。在Java语言中,就只有有符号数,这样省去了很多不必要的麻烦。
有符号数和无符号数在进行强制转换时可能会引起程序的错误,而当这种转换是隐式的时候,错误很难被发现,因而程序会得出莫名其妙的结果。很多函数也因为这种强制转换而存在漏洞,被有心人利用,比如getpeername函数,如果对一个补码的最小值按照无符号数来读,这样就会读出一个很大的数值,如果这个值代表一个地址,那么就可能会产生越界或者读到一些不被授权的信息。