二进制位运算练习

复习一下二进制中的位运算,写些单元测试练习一下

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

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