先看一道例题帮助理解
题目传送门
这道题掌握算法的思路之后用js写会遇到很多坑,>>(超时)和>>>(正确)
下面主要介绍一下这个问题,看似简单,其实里面还真涉及到不少东西,认真看哦!看完了就对移位运算和js数据类型会有一个很好的掌握。
先说明几点:
1.javascript中默认都是带符号的整数,注意是整数,总共32位(含符号位)。
数值范围从 -2^31 - 2^31-1 即 -2147483648 到 2147483647。
2.javascript采用实际表示用64位标准双精度存储的,1 位符号位11 位指数位 52 位尾数位。
下面切入正题:
对于测试用例2 -2147483648
我们用快速幂的方法求解,开始判断如果是负数就转为正数[2^(-3) = 1/(2^3) = (1/2)^3],相当于求其倒数的正数次幂,这个我们应该不难理解。下面问题来了,
1.将-2147483648转成正数2147483648,超出了默认的带符号整数表示范围(默认最大2147483647)
原因:虽然超出了默认的范围,js内部会自动转换成无符号整数,这个肯定没有超出范围
(js中的最大最小安全值)
console.log(Number.MAX_SAFE_INTEGER); //9007199254740991 2^53 -1
console.log(Number.MIN_SAFE_INTEGER); //-9007199254740991 2^53 -1
2.接下来就是移位运算的问题
重点来啦!
(1)>> ,<<表示算数移位,移动时要考虑符号位(下面举例都是默认带符号位,最左边位符号位)
1101(-3)算术右移1位 1110(-2); 1101(-3)算术左移1位 11010(-6)
010(2)算术右移1位001(1); 010(2)算术左移1位0100(4);
(2) >>>,<<<表示逻辑移位,整体左右移,缺位补0(下面举例都是默认带符号位,最左边位符号位)
1101逻辑右移1位 0110; 1101逻辑左移1位 1010
010逻辑右移1位001; 010逻辑左移1位100;
在当前测试用例下,如果用算术移位,转成正数的2147483648(超出带符号表示默认转成无符号表示)正好是2^31,(10000……,31个0)最高位占用了符号位,在第一次循环的时候还是按照无符号整数进行运算进入到循环,当进行移位运算的时候如果选算术移位,就会把这个无符号数看成带符号数进行运算,移位之后n变成负数,退出循环,所以这种情况下循环只进行了一次。采用逻辑移位的话就不会出现这个问题,当然用Math.floor(n/2)的形式也相当于逻辑移位,就解决了这个bug.