Loading... # 预备知识 在计算机中,数据以二进制形式储存,整形数也不例外,下面我们先复习一下整形数的储存。如果没有特殊说明,下面均以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 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏