複習一下二進制中的位運算,寫些單元測試練習一下
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
/**
* 位運算測試
*/
public class BitCalc {
/**
* 異或運算 ^ </br>
* 運算規則:相同爲0,不同爲1
*/
@Test
public void testXor() {
// int long 同理
byte a = 'a';
System.out.println("a = " + a);
byte b = 'b';
System.out.println("b = " + b);
int c = a ^ b;
System.out.println("c = a ^ b = " + c);
System.out.println("c ^ a = " + (c ^ a));
System.out.println("c ^ b = " + (c ^ b));
Assert.assertTrue((c ^ a) == b);
Assert.assertTrue((c ^ b) == a);
// a與b交換
a ^= b;
b ^= a;
a ^= b;
System.out.println("a = " + a);
System.out.println("b = " + b);
Assert.assertTrue((a ^ b) == c);
int source = -14;
int s = ~source + 1;// 求相反數,原理同求補碼:反碼+1,等效於(source ^ -1) + 1 和
// ~(source-1)
Assert.assertTrue(s == -source);
int x = a;
x = a ^ b ^ x;
}
/**
* 與運算 & </br>
* 運算規則:都爲1時爲1,其他爲0
*/
@Test
public void testAnd() {
byte a = 1 & 1;
Assert.assertTrue(a == 1);
int count = 100000;
Assert.assertTrue((count & 1) == (count % 2));
// 取模運算轉化成位運算 (在不產生溢出的情況下) a % (2^n) 等價於 a & (2^n - 1)
for (int i = 1; i < count; i++) {
for (int j = 2; j < 10; j++) {
if (i % (2 << j) == 0) {
Assert.assertTrue((i & ((2 << j) - 1)) == 0);
}
if ((i & ((2 << j) - 1)) == 0) {
Assert.assertTrue((i % (2 << j) == 0));
}
}
}
}
/**
* 右移運算 >> </br>
* 運算規則:將二進制字節右移n位,高位補符號位,低位丟棄
*/
@Test
public void testShiftRight() {
int a = 8 >> 3;
Assert.assertTrue(a == 8 / (2 * 2 * 2));
// (byte) 256=0
System.out.println((byte) 256);
// =》-1
System.out.println((byte) (-5 >> 8 & 0xFF));
// int轉byte
int sum = -128;
System.out.println(Integer.toBinaryString(sum));
// int點4個字節
byte[] intByte = new byte[4];
for (int i = 0; i < 4; i++) {
int n = (3 - i) * 8;
// & 0xFF取低8位,好像不需要& 0xFF,強制轉換成byte,只取了後8位,前24位丟棄了
intByte[i] = (byte) (sum >> n & 0xFF);
}
System.out.println(Arrays.toString(intByte));
System.out.println(abs(-5));
}
/**
* 計算絕對值
*/
private static int abs(int x) {
int y;
y = x >> 31;
return (x + y) ^ y; // 補碼轉原碼算法
}
/**
* 左移運算 << </br>
* 運算規則:將二進制字節左移n位,低位補0,高位丟棄
*/
@Test
public void testShiftLeft() {
int a = 8 << 3;
Assert.assertTrue(a == 8 * (2 * 2 * 2));
// byte轉int
// 11111111 11111111 11111111 11111111=-1
byte[] intByte = new byte[] { -1, -1, -1, -1 };
// =》11111111 00000000=-256
System.out.println(intByte[0] << 8);
// =》00000000 00000000 11111111 00000000=65280
System.out.println(intByte[0] & 0xFF << 8);
int sum = 0;
for (int i = 0; i < 4; i++) {
int n = (3 - i) * 8;
// & 0xFF補零擴充到32位
sum += intByte[i] & 0xFF << n;
}
System.out.println(sum);
System.out.println(Integer.toBinaryString(sum));
// new byte[] { 1, 2, 3, 4 }
System.out.println(Integer.valueOf("00000001000000100000001100000100", 2));
}
/**
* 求平均數 </br>
* @see
* x|y = x&y + x^y </br>
* </br>
* x|y原理:可以理解成同時爲1的部分(x&y),加上不同時不1的部分(x^y)</br>
* </br>
* x+y = 2(x&y) + x^y </br>
* x+y = x|y + x&y </br>
* </br>
* x+y原理:把x和y分別拆開成兩部分,將4個部分相加</br>
* 第一部分爲x和y的二進制碼中同時爲1的部分(也就是x&y),</br>
* 第二部分爲剩下的一個是1,一個是0,或是兩個都是0(也就是x|y)</br>
*
*/
@Test
public void average() {
int x = Integer.MAX_VALUE;
int y = Integer.MAX_VALUE - 1;
// int z = (x + y) / 2; =-2,溢出
System.out.println(((x & 1) + (y & 1)) / 2);
System.out.println(x / 2 + y / 2 + ((x & 1) + (y & 1)) / 2);
int z = (x & y) + ((x ^ y) >> 1);
System.out.println(z);
z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1);
System.out.println(z);
}
/**
* 位操作進行二進制逆序 </br>
* 數34520的二進制表示: 10000110 11011000</br>
* 逆序後則爲: 00011011 01100001 它的十進制爲7009
*/
@Test
public void oppsiteOrder() {
short a = (short) 34520;
System.out.println(Integer.toBinaryString(a & 0xFFFF));
//前8位與後8位對換
a = (short) ((a >> 8 & 0x00FF | a << 8 & 0xFF00));
System.out.println(Integer.toBinaryString(a & 0xFFFF));
//前後8位中的4位相互對換
a = (short) ((a >> 4 & 0x0F0F | a << 4 & 0xF0F0));
System.out.println(Integer.toBinaryString(a & 0xFFFF));
//每相鄰2位相互對換
a = (short) ((a >> 2 & 0x3333 | a << 2 & 0xCCCC));
System.out.println(Integer.toBinaryString(a & 0xFFFF));
//每相鄰1位相互對換
a = (short) ((a >> 1 & 0x5555 | a << 1 & 0xAAAA));
System.out.println(Integer.toBinaryString(a & 0xFFFF));
String str = "123456789";
byte[] strBytes = str.getBytes();
for (int i = 0, len = strBytes.length; i < len / 2; i++) {
strBytes[i] ^= strBytes[len - i - 1];
strBytes[len - i - 1] ^= strBytes[i];
strBytes[i] ^= strBytes[len - i - 1];
}
// 987654321,不適合包含中文的字符串
System.out.println(new String(strBytes));
}
}
參考:
https://www.zhihu.com/question/38206659
https://blog.csdn.net/black_OX/article/details/46411997