留几个 demo 放在前面,大家先计算下结果然后对照。这几个 demo 会出现在我们讲解和探索的过程中。
let a = ~0b01111111111111111111111111111111111111111111111111111111;
console.log(a);
let b = ~0b0111111111111111111111111111111111111111111111111111;
console.log(b);
let c = 2 >> 1;
let d = 2 >> 32;
let e = 2 >> 31;
let f = 2 >> 64;
let g = 2 >> 65;
console.log(c, d, e, f, g);
let h = ~0b11100110111110100000000000000110000000000001;
console.log(h);
答案
吐槽下 CSDN 的 markdown 竟然不支持解析 html 代码
看到实际计算结果和自己计算的结果有没有和惊讶?现在开始解释为什么。
在 js 中,只有浮点数没有严格意义上的整数,每个数字的长度为 64 bits。浮点数的存储遵循 IEEE 754 规范。关于此规范的详细解释请参考 《IEEE 754》(wiki) 和 《IEEE 754》(baidu)。
53根据这个规范,js 中能绝对正确表达的正数为 9007199254740991,也就是 0b111...11
(53个1)。当你对超过这个位数的整数做 ~
就会带来不确定。例如:
// 0
~0b11111111111111111111111111111111111111111111111111111
// -1
~0b1111111111111111111111111111111111111111111111111111110000000
// -1
~0b1111111111111111111111111111111111111111111111111111111
// 3
~0b1111111111111111111111111111111111111111111111111111100
这里还需要特别注意 53 这个数字。因为超过这个长度的数字实际存储的值已经和我们逻辑上表示的值不一样,这时候做位运算会带来不确定的结果。
32js 在做位运算的时候,会把 64 位的数字裁剪为 32 位(从低位到高位的顺序保留 32 位),然后用这 32 位做位运算,然后把计算结果通过向高位补充数字的方式拓展为 64 位。补的方式为:和计算结果(32 位)的最高位相同。
这里需要注意的是,最后还原的二进制是补码,需要通过减 1 然后按位取反的方式还原为原码才能计算真正表示的值。
在做 >>
和 <<
*** 作时,需要注意, *** 作符右侧会进行求余 *** 作(对 32 求余),然后根据得到的余数做位移。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)