位运算Pow(double x , int n)
首先我们要知道, +, -, * ,/ 其实底层都是通过位运算来是实现的
那么都有哪些位运算?
-
~ 取反
-
& 与
-
|或
-
^ 异或
-
<< 左移
-
注意: 是没有无符号左移的, 为什么呐? 如果不知道就是你计算机组成原理没有好好学, 计算机组成原理中讲的很明白, 移位运算分为逻辑移位和算术移位, 那么这里我们是算数移位我们这里就讲算数移位
- 首先我们要知道移位运算肯定是ALU(算数逻辑单元)完成的
- 那么ALU中每当给算数移位一次之后这个时候相应的就会在高位或者是低位产生一个空位, 这个时候我们要给这个空位补什么?
- 如果是算数右移 : 那么是高位出现了一个空位, 而我们知道高位其实是符号位, 这个时候我们设计到给符号位补一个值, 那么我们到底是给高位补一个0, 还是补原本的符号位? —> 这就引出了无符号右移和有符号右移
- 如果是算数左移 : 那么低位出现了一个空位, 没办法, 高位(符号)我们留不住, 所以这个时候我们只是涉及到低位空位的补位, 那么低位我们肯定是补一个0就可以了
- 最后给大家一点忠告 : 记得! 如果你要手推这些位运算的时候, 首先搞清楚计算机底层做这些运算的时候往往都是用不补码运算的
-
-
(>>) 右移 —> 这里因为打不出来>>所以就加了一个()
-
(>>>) 无符号右移
这里给大家普及一个小知识, -(负号)x在底层是如何实现的? 其实就是给~(取反号)x + 1, 也就是先给x进行一个取反, 然后加1 —> 所以我们其实就可以在代码中来实现求一个数的负数的时候直接写成取反 + 1
这里再给大家普及一个小知识, 如果是int类型的Integer.MIN_VALUE值, 如果我们写一个-Integer.MIN_VALUE然后打印可以看一下, 还是这个负数 —> 那么这又是因为什么? —> 哈哈, 因为就是因为 -x其实就是x的取反加一, 但是如果我们将Integer.MIN_VALUE的二进制打印出来之后我们可以发现, 其实底层是用负零(10000000000000000000000000000000)来表示这个值的 —> 这个如果你想要知道是为什么, 可以去学习计算机组成原理这门课, 那么我们可以对这个值进行一个取反加一 —> 我们可以发现, 我们又得到了这个数, 所以说这就是为什么Integer.MIN_VALUE求绝对值之后还是Integer.MIN_VALUE的原因
通过力扣的Solution50来理解位运算:
50. Pow(x, n)
实现 pow(x, n) ,即计算 x
的整数 n
次幂函数(即,x ^ n)
- 题目中说明n的取值范围是:
-2 ^ 31 <= n <= 2 ^ 31 - 1
实现:
暴力解法:
最简单的解法就是暴力解法, 就是我们直接x乘上一个n次就可以了, 简单暴力 , 但是该题目是一个中等题, 所以肯定不是让我们用暴力解法来完成
进阶解法:
对于这种java底层的MathAPI实现, 这个时候其实大家应该要想到位运算, 那么我们如何使用位运算实现?
题目中告诉我们: n虽然是有可能为正数有可能为负数, 但是始终是一个整数, 那么这个题目就好做了, 如下图:
不知道为啥, 截图很模糊, 可能还是没有充钱, 哈哈
我们直接给出进阶解法代码:
public double myPow(double x, int n) {
if(n >= 0) {
return privatePow(x, n);
}else {
//判断n是否是一个最小负整数, 如果是, 那么要做一个特殊判断
if(n == Integer.MIN_VALUE) {
//如果n为Integer.MIN_VALUE值, 这个时候我们无法对该值去一个绝对值
return 1 / privatePow(x, Math.abs(n - 1)) * x;
}else{
return 1 / privatePow(x, Math.abs(n));
}
}
}
//求一个double类型的值的n次方 --> 要求n必须为正数
private double privatePow(double x, int n) {
int temp = n;
//起始的时候定义一个x, 表示的是基数, 我们每次要使用该基数去做t = t * t
double t = x;
//定义返回结果
double res = 1d;
while(n != 0) {
//只要n值不为0, 即使是一个小数, 这个时候继续运算, 说明还有位数
if((n & 1) != 0){
res = res * t;
}
//将n右移一位
n = n >> 1;
//更新t
t = t * t;
}
return res;
}
- 主要就是对负数求 ^ n的时候和对Integer.MIN_VALUE求 ^ n的时候做的特殊判断以及对应的处理操作