预备知识

在计算机中,数据以二进制形式储存,整形数也不例外,下面我们先复习一下整形数的储存。如果没有特殊说明,下面均以byte(8位)来说明。

原码

符号位数值位
1位7位

符号位

0 = 正数

1 = 负数

数值位

将数转化为二进制储存,高位在前,溢出则丢弃高位,不足左边补0。

反码

负数的数值位按位取反,例如-20的原码为1 0010100,反码为1 1101011

$$ \begin{matrix} True Form&1&0010100\\ Complement&1&1101011 \end{matrix} $$

补码

正数的补码和原码相同,负数的补码为反码 + 1 (若溢出则丢弃高位)。

移码

数值位于补码相同,但符号位,但符号位相对补码取反,即 0 = 负数,1 = 正数。

为什么要有反码和补码

我们希望有一种表示方法,可以使两个数的加法可以直接相加。
对于正数相加,结果是正确的

$$ \begin{matrix} 16 &&0&0010000\\ 20 &+&0&0010100\\ Ans&=&0&0100100\\ Ans&=&&36 \end{matrix} $$

但对于负数

$$ \begin{matrix} -16 &&1&0010000\\ 20 &+&0&0010100\\ Ans &=&1&0100100 \\ Ans&=&&-36 \end{matrix} $$

正数的原码就是它的二进制表示,结果当然是正确的,但对于负数,情况却不是这样,思考一下我们进行加法运算时,我们需要对正数和负数进行不同的处理,加上一个负数等于减去它的相反数,对于计算机来说,加法运算有两个操作数,也就是有四种情况,一共4种情况,显然计算机这样设计是不方便的。

考虑反码

$$ \begin{matrix} -16 &&1&1101111\\ 20 &+&0&0010100\\ Ans &=&1&0000011\\ Ans&=&&3 \end{matrix} $$

与正确结果已经很接近了,这里是问题是-0导致的。

如果我们给原码+1

$$ \begin{matrix} -16 &&1&1110000\\ 20 &+&0&0010100\\ Ans &=&1&0000100\\ Ans&=&&4 \end{matrix} $$

结果正确。这就是补码。

为什么我们需要移码

负数使用补码表示,我们可以很方便地进行加法,如果我们把符号位取反,我们就可以按位比较两个数的大小了。

位运算

位运算的对象是整型数,正数用原码表示,负数用补码表示。下表是Java语言中的位运算表。

操作符名称描述
如果相对应位都是1,则结果为1,否则为0
如果相对应位都是 0,则结果为 0,否则为 1
^异或如果相对应位值相同,则结果为0,否则为1
~取反按位取反,0 -> 1,1 -> 0。
<<左移所有位左移,右边补0。相当于 * 2^n。
\>>右移所有位右移,左边补符号位。相当于 / 2^n。
\>>>无符号右移所有位右移,左边补0。相当于无符号数 / 2^n。

$$ \begin{matrix} -16 &&1&1110000\\ 20 &&0&0010100\\ Ans &=&0&001 0000\\ Ans&=&&16\end{matrix} $$

与运算可以将某些位清零,另外,在判断整型数是奇数还是偶数的时候,可以用来代替 % 2,因为二进制下奇数的末尾是1,number&1的结果是1。

$$ \begin{matrix} -16 &&1&1110000\\ 20 &&0&0010100\\ Ans &=&1&1110100\\ Ans&=&&-12\end{matrix} $$

或运算可以将某些位设位1。

异或

$$ \begin{matrix} -16 &&1&1110000\\ 20 &&0&0010100\\ Ans &=&1&1100100\\ Ans&=&&-28\end{matrix} $$

异或运算可以将某些位取反,由于Java语言中没有同或,我们可以用~(n^i)表示同或运算。

$$ \begin{matrix} -16 &&1&1110000\\ Ans &=&0&0001111\\ Ans&=&&15\\\\ 20 &&0&0010100\\ Ans &=&1&1101011\\ Ans&=&&-21\end{matrix} $$

事实上,对于逻辑非,在不发生溢出的情况下,总有i + (~i) = -1 成立。

左移

$$ \begin{matrix} -16 &&1&1110000\\ <<1 &=&1&1100000\\ Ans&=&&-32\\\\ 20 &&0&0010100\\ <<1 &=&0&0101000\\ Ans&=&&40\end{matrix} $$

相当于算数左移或者逻辑左移。

右移

$$ \begin{matrix} -16 &&1&1110000\\ >>1 &=&1&1111000\\ Ans&=&&-8\\\\ 20 &&0&0010100\\ >>1 &=&0&0001010\\ Ans&=&&10\end{matrix} $$

相当于算数右移。

无符号右移

$$ \begin{matrix} -16 &&1&1110000\\ >>>1 &=&0&1111000\\ Ans&=&&120\\\\ 20 &&0&0010100\\ >>>1 &=&0&0001010\\ Ans&=&&10\end{matrix} $$

相当于逻辑右移(即不考虑符号)。

但上面有关-16的右移是错误的,无符号位移只对32位(int)或者64位(long)整型起作用,在Java中,无符号右移的两个操作数至少是int,结果也是int。下面是正确的分析。

$$ \begin{matrix} 16 &&00000000\space00000000\space00000000\space00010000\\ -16 &&00111111\space11111111\space11111111\space11111100\\ >>>1 &=&00111111\space11111111\space11111111\space11111100\\ Ans&=&2147483640 \end{matrix} $$

最后修改:2020 年 03 月 26 日
如果觉得我的文章对你有用,请随意赞赏