JS中遇到的二进制位运算问题
知识点:
JS中的负值是通过补码来进行保存的,补码的计算流程就是:
- 确定绝对值的二进制表示(如,对于-18,先确定18 的二进制表示);
- 找到数值的一补数(或反码),换句话说,就是每个0 都变成1,每个1 都变成0;
- 给结果加1。
而补码转换回十进制的方法就是:
- 补码减1
- 按位取反
位运算
遇到过这样一个语句,不是很理解原理:
i = i | 0;
后来在网上找到了资料解释很清晰:二进制位运算符
即位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。
这个语句实现的效果就是将一个浮点数的小数部分忽略。位运算会自动忽略小数部分,与0进行或操作又会返回自身的值,因此达到了这么一个忽略小数的效果。
function toInt32(x) {
return x | 0;
}
toInt32(1.001) // 1
toInt32(1.999) // 1
toInt32(1) // 1
toInt32(-1) // -1
toInt32(Math.pow(2, 32)) // 0
toInt32(Math.pow(2, 32) + 1) // 1
toInt32(Math.pow(2, 32) - 1) // -1
ECMAScript中的所有数值都以IEEE 754 64 位格式存储,但位操作并不直接应用到64 位表示,而是先把值转换为32 位整数,再进行位操作,之后再把结果转换为64 位。
注意这里虽然是位运算最多操作32位整数,但由于默认ECMAScript 中的所有整数都表示为有符号数,所以第32位是符号位,所以实际位运算能正确处理的数值大小只有 [ − 2 31 , 2 31 − 1 ] [-2^{31}, 2^{31}-1] [−231,231−1]这个范围。
其实准确来说应该是 ( − 2 31 − 1 , 2 31 ) (-2^{31}-1, 2^{31})