我正在尝试在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
。这里发生了什么?
答案 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;
负数不会直接表示值。
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位整数。
您的num
为2147483647
,此编号采用二进制补码格式:
01111111 11111111 11111111 11111111
将num
左移{后,它变为:
11111111 11111111 11111111 11111110
以上32位二进制补码值为十进制数-2
。因此,你得到:
> num
2147483647
> num << 1
-2
如果您使用负十进制数toString(2)
致电-2
,则会遵循一些特殊规则toString()
。它的作用是:
-2
=&gt; 2
)2
=&gt; '10'
)'10'
=&gt; '-10'
)因此,你得到:
> (num << 1).toString(2)
> -10
你也得到:
> (-2).toString(2)
> -10