位运算 - 加减乘除 和 取模

代码如下:

package class05;

/**
 * 位运算实现 + - * /
 * 手写的 + - * / 不如 java自带的+ - * / 快, 这是当然了,你自己写一个方法去实现,肯定不如人家一条语句快
 *  i>>6 肯定比 i/64 要快, i & 63 肯定要比 i % 64 要快
 *
 *  其它知识点:
 *  位运算基本操作,按位与,按位或,按位异或,左移,右移等, 怎样利用这些操作去实现 + - * / % 这5个操作???
 *  异或运算,在位运算看来就是无进位相加, 任何一位相加之后产生的进位都抛弃。
 *  怎样得到进位信息? 按位与之后,整体左移 1 位
 */
// 测试链接:https://leetcode.com/problems/divide-two-integers  力扣原题,也得做一下
public class Code03_BitAddMinusMultiDiv {

	/**
	 * 1.异或操作 相当于两个数相加,但是每一位相加后,都忽略进位
	 * 2.按位与之后左移 1 位, 相当于拿到了每一位相加后的进位值。(进位补偿值)
	 * 上面的二者相加就是最终的结果,但是不能直接相加,因为不能直接使用+ 运算符,那么怎么把这两个值相加呢?
	 * 上面得出的两个值,再继续进行 异或操作 和 按位与之后左移1位操作,循环执行这个过程,直到进位补偿信息变为0,
	 * 那么就结束了。
	 * @param a
	 * @param b
	 * @return
	 */
	//加法, a + b
	public static int add(int a, int b) {
		int sum = a;
		while (b != 0) {
			sum = a ^ b;
			b = (a & b) << 1;
			a = sum;
		}
		return sum;
	}

	//相反数(不是取反): 相反数是取反之后 + 1, 我们这里用add实现
	//整数取反之后,其最高位变为1,表示负数。同理,负数取反之后,变为正数
	public static int negNum(int n) {
		return add(~n, 1);
	}

	//减法, 等于 a + (-b)
	public static int minus(int a, int b) {
		return add(a, negNum(b));  //将b取 相反数(不是取反,别搞错了),相反数 = 取反 + 1, 取反可以把正数变为负数
	}

	//乘法, 跟十进制数字相乘的算法是一致的。
	public static int multi(int a, int b) {
		int res = 0;
		while (b != 0) {
			if ((b & 1) != 0) {
				res = add(res, a);
			}
			a <<= 1; // a要左移1位,相当于补了1个0(每次循环都要补0)
			b >>>= 1; //让b不断右移
		}
		return res;
	}

	//判断是否为负数
	public static boolean isNeg(int n) {
		return n < 0;
	}

	//除法
	public static int div(int a, int b) {
		int x = isNeg(a) ? negNum(a) : a;
		int y = isNeg(b) ? negNum(b) : b;
		int res = 0;
		for (int i = 30; i >= 0; i = minus(i, 1)) {
			if ((x >> i) >= y) {
				res |= (1 << i);
				x = minus(x, y << i);
			}
		}
		return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
	}

	//除法
	public static int divide(int a, int b) {
		if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
			return 1;
		} else if (b == Integer.MIN_VALUE) {
			return 0;
		} else if (a == Integer.MIN_VALUE) {
			if (b == negNum(1)) {
				return Integer.MAX_VALUE;
			} else {
				int c = div(add(a, 1), b);
				return add(c, div(minus(a, multi(c, b)), b));
			}
		} else {
			return div(a, b);
		}
	}

	public static void main(String[] args) {
		int a = 7;
		int b = -3;
		//乘法为什么支持b为负数,这个很难解释,跟补码有关,这里就不解释了
		System.out.println(multi(a,b)); //-21


		//正常取模
		int i = 11;
		int result = i % 10;
		System.out.println(result);


		/**
		 * 通过 1 次位运算实现取模,能不能够实现? 可以实现,但是实在某些特定条件下,什么特定条件?? 对谁取模, 只有对2^n取模的时候,
		 * 才能使用1次位运算实现取模。所以这里对10取模,是不能通过1次位运算实现的。
		 */
		/**
		 * 10: 000000000 00000000 00001010
		 * 11: 000000000 00000000 00001011
		 *
		 */
		int result1 = i & 9;
		System.out.println(result1);

		/**
		 * 对64进行取模运算, 64 = 2^6, 可以通过1次位运算来实现。
		 * 63: 00000000 00000000 00111111 32+16+8+4+2+1 = 63
		 * 与63进行按位与,在1区域左侧的数据,都被抹掉了,剩下的值就是取模的值
		 */
		int result2 = 65 & 63;
		System.out.println(result2);
	}

}

乘法原理如下:

与普通整数之间的乘法是一致的。

除法原理如下:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值