与左移操作员混淆

时间:2018-01-30 05:37:08

标签: javascript bit-manipulation

我正在尝试在JS中创建一个32位的位掩码。但是,我不明白这里发生了什么:

$ node
> const num = Math.pow(2, 31) - 1
undefined
> num
2147483647

# So far, so good
> num.toString(2)
'1111111111111111111111111111111'
> num.toString(2).length
31

# According to MDN, the left-shift operator does:
# "Excess bits shifted off to the left are discarded. 
#    Zero bits are shifted in from the right."
# But that's not what we see here. Instead, it seems to be wrapping.
> num << 1
-2
> (num << 1).toString(2)
'-10'

根据我对the MDN docs的理解,我预计会有一个31 1 s后跟1 0的位掩码。相反,我得到-10。这里发生了什么?

3 个答案:

答案 0 :(得分:2)

Javascript没有Integer,但按位运算符只对Integer有意义。

因此,在按位运算符之前,javascript会将ToInt32(val)应用于您的数字

对于&#34;有符号32位整数&#34;,最高位代表&#39;签名&#39;。

最后你的数字溢出了#39;签名位&#39;。

我的英语很差,你可以查看ECMAScript的语言规范。

答案 1 :(得分:1)

今天我再次检查你的问题,然后知道我昨天误解了你的要点。

这是你的要点: &#34;我希望有一个31 1 s后跟1 0的位掩码。相反,我得到-10。&#34;

因为Two's complement

负数不会直接表示值。

let num=Math.pow(2,31)-1
//num in memory=> 0111111111111111111111111111111
//                ^ 
//                |
//            signed bit
//This number is positive, so
//nothing to do=> 0111111111111111111111111111111

num = num<<1
//num in memory=> 1111111111111111111111111111110
//                ^ 
//                |
//            signed bit
//This number is negative, so flip then add 1
//flip         => 1000000000000000000000000000001
//add 1        => 1000000000000000000000000000010 => '-10'

答案 2 :(得分:1)

它不是包装。它与您链接的文档完全一致。在您的链接文档中,它说:

  

所有位运算符的操作数都以二进制补码格式转换为带符号的32位整数。

您的num2147483647,此编号采用二进制补码格式:

01111111 11111111 11111111 11111111

num左移{后,它变为:

11111111 11111111 11111111 11111110

以上32位二进制补码值为十进制数-2。因此,你得到:

> num
2147483647
> num << 1
-2

如果您使用负十进制数toString(2)致电-2,则会遵循一些特殊规则toString()。它的作用是:

  1. 取小数的精神。 (-2 =&gt; 2
  2. 将小数转换为base-2字符串表示形式。 (2 =&gt; '10'
  3. 将减号放在前面。 ('10' =&gt; '-10'
  4. 因此,你得到:

    > (num << 1).toString(2)
    > -10
    

    你也得到:

    > (-2).toString(2)
    > -10