您的位置:首页 > 编程语言 > Java开发

Java中的位操作

2016-04-21 14:20 549 查看

1 机器码

要进行位操作,首先得了解数据以二进制保存的形式吧。这里我们只以定点数讲解,即原码、反码、补码的知识。浮点数的机器码比较复杂,一般不会考到浮点数的位操作。

这里我只强调几点:

整数0的机器码是32位全为0;

32位全为1的整数是-1;

首位为0,其余31位为1的数就是 int 所能表示的最大正整数;

符号位为1,其余位全为0的不是 -0 ,而是int所能表示的最小负整数;

整数的机器码是以其补码形式表示的,所以整数的补码很直观,但是负数的可能就不那么直观了。

public static void main(String[] args) {
for (int i = 0; i < 9; i++) {
System.out.printf("i = %d\n   机器码:%-6s ;变负数:%-6s ; 取反:%-6s\n", i, Integer.toBinaryString(i),
Integer.toBinaryString(-i), Integer.toBinaryString(~i));
}
String MAX_VALUE = Integer.toBinaryString(Integer.MAX_VALUE);
String MIN_VALUE = Integer.toBinaryString(Integer.MIN_VALUE);
System.out.printf("\nInteger.MAX_VALUE: %d ; 机器码为:%s ; 长度:%d\n", Integer.MAX_VALUE, MAX_VALUE,
MAX_VALUE.length());
System.out.printf("Integer.MIN_VALUE: %d ; 机器码为:%s ; 长度:%d\n", Integer.MIN_VALUE, MIN_VALUE,
MIN_VALUE.length());
}


i = 0
机器码:0      ;变负数:0      ; 取反:11111111111111111111111111111111
i = 1
机器码:1      ;变负数:11111111111111111111111111111111 ; 取反:11111111111111111111111111111110
i = 2
机器码:10     ;变负数:11111111111111111111111111111110 ; 取反:11111111111111111111111111111101
i = 3
机器码:11     ;变负数:11111111111111111111111111111101 ; 取反:11111111111111111111111111111100
i = 4
机器码:100    ;变负数:11111111111111111111111111111100 ; 取反:11111111111111111111111111111011
i = 5
机器码:101    ;变负数:11111111111111111111111111111011 ; 取反:11111111111111111111111111111010
i = 6
机器码:110    ;变负数:11111111111111111111111111111010 ; 取反:11111111111111111111111111111001
i = 7
机器码:111    ;变负数:11111111111111111111111111111001 ; 取反:11111111111111111111111111111000
i = 8
机器码:1000   ;变负数:11111111111111111111111111111000 ; 取反:11111111111111111111111111110111

Integer.MAX_VALUE: 2147483647 ; 机器码为:1111111111111111111111111111111 ; 长度:31
Integer.MIN_VALUE: -2147483648 ; 机器码为:10000000000000000000000000000000 ; 长度:32


MAX_VALUE / MIN_VALUE

MAX_VALUE

值为 2^31 -1 的常量,它表示 int 类型能够表示的最大值。

MIN_VALUE

值为 -2^31 的常量,它表示 int 类型能够表示的最小值。

为什么是31位而不是32位呢?因为最高位是符号位。第一位bit的基是2^0,第二位bit的基是2^2,……,第31位的基是2^30。所以MAX_VALUE的值为 2^31 -1,这个减一是经常容易被忽略的。那为什么10000000000000000000000000000000可以表示最小值呢? 因为这是一个巧妙的约定。

int t1 = Integer.MAX_VALUE;
System.out.printf("Integer.MAX_VALUE is: %d; the bitString is: %s\n", t1, Integer.toBinaryString(t1));
t1++;
System.out.printf("Integer.MAX_VALUE++ is: %d; the bitString is: %s\n", t1, Integer.toBinaryString(t1));

int t2 = Integer.MIN_VALUE;
System.out.printf("Integer.MIN_VALUE is: %d; the bitString is: %s\n", t2, Integer.toBinaryString(t2));
t2--;
System.out.printf("Integer.MIN_VALUE-- is: %d; the bitString is: %s\n", t2, Integer.toBinaryString(t2));


Integer.MAX_VALUE is: 2147483647; the bitString is: 1111111111111111111111111111111
Integer.MAX_VALUE++ is: -2
bbf6
147483648; the bitString is: 10000000000000000000000000000000
Integer.MIN_VALUE is: -2147483648; the bitString is: 10000000000000000000000000000000
Integer.MIN_VALUE-- is: 2147483647; the bitString is: 1111111111111111111111111111111


Java运算符的优先级



这里我们着重关注一下位移运算(左移<<、右移>>、无符号右移>>)的优先级,它们的优先级甚至低于加和减,但高于位运算。

java中>>与>>>的区别

有符号右移运算符>>

用来将一个数的各二进制位全部右移若干位。例如:a = a>>2,使a的各二进制位右移两位,移到右端的低位被舍弃,最高位则移入原来高位的值。如:

a = 00110111,则a>>2=00001101

b=11010011,则b>>2 = 11110100

右移一位相当于除2 取商,而且用右移实现除法比除法运算速度要快。

无符号右移运算符>>>

用来将一个数的各二进制位无符号右移若干位,与运算符>>相同,移出的低位被舍弃,但不同的是最高位补0,如:

a = 00110111,则a>>>2 = 00001101

b=11010011,则 b>>>2 = 00110100

位运算实例

题目:

m 为正整数。

将 n 的二进制码中的 i–j 位的bit位换成 m的二进制码。

i是低位 j是高位。

i和j的设置一定与m和n的情况相符,不会出现异常。

代码

public static int updateBits(int n, int m, int i, int j) {
System.out.printf("n: %s ; m: %s\n\n", Integer.toBinaryString(n), Integer.toBinaryString(m));
System.out.println("---------- Build mask ----------");
int full1 = ~0; // 全1

// 低位有 j+1 个0, 高位全为1
int left = full1 << j + 1;
System.out.printf("The left of mask is: %s\n", Integer.toBinaryString(left));

// 高位全为0,低位有i个1
int right = full1 >>> (32 - i);
System.out.printf("The right of mask is:    %s\n", Integer.toBinaryString(right));

// Left和right进行按位或运算,就可以得到 i--j 位为0,其余位全为1的mask
int mask = left | right;
System.out.printf("The mask is: %s\n\n", Integer.toBinaryString(mask));

// 用 mask 将 n 上 i--j 位清零
int maskN = mask & n;
System.out.printf("Mask n and result is:    %s\n", Integer.toBinaryString(maskN));

// 将 m 右移 i 位,与清零后的n 或
int insertRest = maskN | (m << i);
System.out.printf("Insert result is:    %s\n", Integer.toBinaryString(insertRest));
return insertRest;
}


输出

n: 10000000000000000000000000000000 ; m: 10011

---------- Build mask ----------
The left of mask is:    11111111111111111111111110000000
The right of mask is:   11
The mask is:    11111111111111111111111110000011

Mask n and result is:   10000000000000000000000000000000
Insert result is:   10000000000000000000000001001100
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息