【问题标题】:Confusion with left-shift operator与左移运算符混淆
【发布时间】:2018-01-30 05:37:07
【问题描述】:

我正在尝试在 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 个1s,后跟1 个0。相反,我得到-10。这是怎么回事?

【问题讨论】:

标签: javascript bit-manipulation


【解决方案1】:

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

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

对于“有符号的 32 位整数”,最高位表示“有符号”。

最后你的 num 溢出了“有符号位”。

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

【讨论】:

    【解决方案2】:

    它没有包装。它与您链接的文档完全相同。在您的链接文档中,它说:

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

    你的num2147483647,这个数字的补码格式是:

    01111111 11111111 11111111 11111111
    

    num左移1后变为:

    11111111 11111111 11111111 11111110
    

    上面的 32 位二进制补码值是十进制数 -2。因此,您得到:

    > num
    2147483647
    > num << 1
    -2
    

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

    1. 取小数位数。 (-2 => 2)
    2. 将十进制转换为 base-2 字符串表示。 (2 => '10')
    3. 将减号放在前面。 ('10' => '-10')

    因此,你得到:

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

    您还可以获得:

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

    【讨论】:

      【解决方案3】:

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

      这是你的主要观点: " 我希望位掩码为 31 1s,后跟 1 0。相反,我得到 -10。"

      因为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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-01
        • 1970-01-01
        • 2019-12-29
        • 2020-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多