二進制位運算練習

複習一下二進制中的位運算,寫些單元測試練習一下

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章