计算机基础——位运算

摘要:
位操作是处理器支持的底层操作,因此运行速度非常快。尽管现代计算机处理器具有更长的指令流水线和更好的架构设计,使得加法和乘法几乎与位运算一样快,但位运算消耗的资源更少。您可能经常在JDK源代码中看到位操作,因此需要掌握位操作。移位运算符的右操作数需要模32运算。如果是长类型,则需要模64运算。XOR运算“^”XOR运算的规则是相同的是0,不同的是1。

位运算操作是由处理器支持的底层操作,因此运行速度很快。尽管现代计算机处理器拥有了更长的指令流水线和更优的架构设计,使得加法和乘法运算几乎与位运算一样快,但是位运算消耗更少的资源。

你可能经常在JDK源码中看到位运算操作,因此对位运算的掌握是有必要的。

举个例子,比如java.lang.Long的hashCode()方法:

    public static int hashCode(long value) {
        return (int)(value ^ (value >>> 32));
    }

这里就用到了异或运算 '^' 和逻辑右移运算 '>>>' ,需要注意到这里面有一个运算符优先级的问题。 优先级的问题看这里。

移位运算符

Java中移位运算有三种,分别是左移运算、算术右移、逻辑右移,对应的操作符是 '<<' 、 '>>' 和 '>>>'。移位运算符的右操作数需要进行模32的运算,如果是long类型,需要进行模64的运算。例如,1 << 35 就等同于 1 << 3。

左移运算 '<<'

左移运算将数字的二进制位全部向高位移动,低位补 0 。例如,数字 23 左移 1 位,即为 23 << 1 ,左移运算的二进制位如下:

            0001 0111 (数字 23 )
左移 1 位 = 0010 1110 (数字 46 )

可以发现,左移 1 位相当于乘以 2 ,而左移 n 位相当于乘以 2 的 n 次方。需要注意的是,可能会导致溢出。

算术右移 '>>' 和 逻辑右移 '>>>'

右移运算与左移运算刚好相反,右移将数字的二进制位全部向低位移动,算术右移高位补符号位,逻辑右移高位补 0 。也就是说,数字 -105 算术右移 1 位,即 -105 >> 1,二进制位如下:

                1001 0111 (数字 -105 )
算术右移 1 位 = 1100 1011 (数字 -53 )

同样地,我们发现算术右移 1 位相当于除以 2 ,由于最低位的值被掩盖了,-105 跟 -106 右移结果将是相同的。
如果是逻辑右移,即 -105 >>> 1,二进制位如下:

                1001 0111 (数字 -105 )
逻辑右移 1 位 = 0100 1011 (数字 75 )

算术右移和逻辑右移的区别就在于,算术右移将补充符号位,逻辑右移将补充 0 。

异或运算 '^'

异或运算的规则是,相同为 0 ,不同为 1 。例如:

       0101
  XOR  0011
    =  0110

结合已经学习的逻辑右移运算和异或运算,回头来看java.lang.Long的hashCode()方法,会发现作者实现得真巧妙。一个较好的hashCode()实现,应该尽量均匀地映射到 int 范围上。long 类型的 value >>> 32 ,会将高 32 位移到低 32 位,然后高 32 位补 0 。如果这个 long 类型的 value 值没有超过 int 类型的表示范围,value >>> 32 的二进制结果将是 64 个 0。即 value ^ ( value >>> 32) 将转换成 value ^ 0,而与 value ^ 0 等于 value。结果就是,当 long 类型的值不超过 int 类型的表示范围时,Long 的hashCode()方法,将直接返回对应的 int 值。也就是说,被完全均匀地 hash 映射。

或运算 '|'

或运算的规则是,有 1 为 1 ,全为 0 时为 0 。例如:

        0101 (数字 5 )
    OR  0011 (数字 3 )
    =   0111 (数字 7 )

或运算可以用来set(1) ,举个例子,二进制数 0010 (数字 2 )通过或运算第四位可以单独被置为 1 :

        0010 (数字 2)
    OR  1000 (数字 8)
    =   1010 (数字 10)

与运算 '&'

与运算的规则是,都为 1 时为 1,有一个为 0 就为 0 。例如:

        0101 (数字 5)
    AND 0011 (数字 3)
    =   0001 (数字 1)

与运算可以用于 clear(0) 操作,或者对特殊的位 set(1),这里的 set(1) 与或运算是不同的,与运算 set(1) 只会让被设置的位为 1 ,例如:

        0011 (数字 3)
    AND 0010 (数字 2)
    =   0010 (数字 2)

因为结果是 0010 ,我们便知道原数字的第 2 位是 1 。这个操作被称为位屏蔽。

再举个例子, 假设 0110 (数字 6 )是一个 4 位标记,第 1 位和第 4 位已经被 clear(0),第 2 位和第 3 位被 set(1)。现在可以通过与运算将第 3 位置为 0 :

        0110 (数字 6)
    AND 1011 (数字 11)
    =   0010 (数字 2)

因为这个特性,与运算可以通过校验最低位的值来进行奇偶校验。例如:

        0110 (数字 6)
    AND 0001 (数字 1)
    =   0000 (数字 0)

因为 6 AND 1 等于 0,也就是说 6 能被 2 整除,所以是偶数。

取反运算 '~'

取反运算的规则是,将二进制的每一位取反,1 变为 0, 0 变为 1。例如:

    NOT 0111 (数字 7)
    =   1000 (数字 8)
    NOT 10101011  (数字 171)
    =   01010100  (数字 84)

免责声明:文章转载自《计算机基础——位运算》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇linux 简介关于计算机学科的一些期刊和会议(转)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ASCII码、HEX、字符、BCD 等等 基础知识思考

每每遇到这些问题就要想个半天,想不明白还不舒服,今天特别把所想整理下避免以后再次进入思想漩涡!!!计算机存储和传输都是以字节为单位1 bit = 1 二进制数据1 byte = 8 bit1 字母 = 1 byte = 8 bit1 汉字 = 2 byte = 16 bit1. bit:位一个二进制数据0或1,是1bit;2. byte:字节存储空间的基本...

汇编语言中的数据类型

目录 一、数制及相互转换 1. N 进制数转换为十进制数 2. 十进制数转换为 N 进制数 3. 二进制数转换为八进制数或十六进制数 4. 八进制数或十六进制数转换为二进制数 二、计算机中数和字符的表示 (一)计算机中数的表示方法 1. 原码表示法 2. 补码表示法 (二)二进制编码 1. 十进制数的二进制编码(BCD 码) 2. 字...

六.HashMap HashTable HashSet区别剖析总结

 HashMap、HashSet、HashTable之间的区别是Java程序员的一个常见面试题目,在此仅以此博客记录,并深入源代码进行分析: 在分析之前,先将其区别列于下面: 1、HashSet底层采用的是HashMap进行实现的,但是没有key-value,只有HashMap的key set的视图,HashSet不容许重复的对象 Hashtable是基...

为枚举类型添加描述信息 this 扩展 泛型约束 位运算[转]

为枚举类型添加描述信息 this 扩展 泛型约束 位运算 2011年10月13日 星期四 上午 10:09     在开发应用中,我们经常用枚举来简化程序。但是让人头的是总得枚举一个别名Alias用于显示或者描述该枚举值,这时候如果我们采用if或者switch的方法来进行判读也可以,但是有点不够优雅。下面来给大家分享一下我的实现方法。今天同事把博客园里的...

JAVA实现二进制,十六进制输出

public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(Integer.toBinaryString(320*1024)); System....

计算机基础第三章:寄存器&amp;amp;内存(Registers&amp;amp;RAM)

寄存器&内存(Registers&RAM) 前言 前面学习了逻辑门和ALU,想要制作一个“CPU”我们还需要学习内存,因为CPU所运算 数据的读写都离不开内存。 一.内存单位 学习内存首先我们要了解存储单位 1TB(太字节)=1024GB(千兆字节) 1GB=1024MB(兆字节) 1MB=1024KB(千字节) 1KB=1024byte(...