【问题标题】:i & 0xFF vs i % 256 with negative numbersi & 0xFF vs i % 256 带负数
【发布时间】:2019-11-01 18:14:10
【问题描述】:

我想知道为什么 (i % 256) 和 (i & 0xFF) 如果 i 为 0 或正数则相同,但如果 i 为负数则完全不同。

用于测试的代码:

i = -100
while (i < 100) {
    if (!((i & 0xFF) == (i % 256))) console.log(i);
    i++;
}

这是为什么?

【问题讨论】:

    标签: javascript bitwise-operators modulo bitwise-and


    【解决方案1】:

    负数用two's complement的形式表示,即-100的二进制表示为

    (2**32 - 100).toString(2) = 11111111111111111111111110011100
    

    添加0xff 得到10011100,即156

    模运算%定义为

    IF a % b == r  THEN a == b * q + r for some q
    

    qr 始终有两种选择,余数为正数和负数。例如,7 % 3

     7 = 3 * 2 + 1
     7 = 3 * 3 - 2
    

    负数也一样,-7 % 3:

     -7 = 3 * (-2) - 1
     -7 = 3 * (-3) + 2
    

    对于正数,所有语言都选择正余数。对于负数,选择因语言而异。例如在python中,余数总是正数,所以

     -7 % 3 = 2   # python
    

    Javascript 选择负余数,所以在 JS 中

     -7 % 3 = -1  // javascript
    

    同样,-100 % 256

    -100 = 256 * ( 0) - 100
    -100 = 256 * (-1) + 156
    

    在 python 中,余数是 156(因此匹配 &amp; FF),在 javascript 中是 -100

    【讨论】:

      【解决方案2】:

      先总结一下运算符:

      &amp; 是按位与运算符。

      • 例如,对于 4 位正数,
      0110 (6)
      0100 (4) &
      -------
      0100 (4)
      
      • 例如,对于 4 位(2 的补码)负数,
      1010 (-6)
      1100 (-4) &
      -------
      1000 (-8)
      

      % 是模运算符。 x % y 大致意思是x - parseInt(x / y) * x

      • 例如,对于正数,8 % 3 === 2
      • 例如,对于负数,-8 % 3 === -2

      现在回答问题

      为了我们的解释,让我们简单地使用 i &amp; 0b0011 (3)1 % 0b0100 (4) 而不是 255 和 256。这对于这个问题的目的是等效的,因为二进制中的 256 是二进制中的 10000...0xff01111...

      • 对于小于 4 的正数:i &amp; 0b00111 % 0b0100 都将返回 i

      2 % 4 = 4

      0010 (2)
      0011 (3) &
      -------
      0010 (2)
      
      • 对于大于或等于 4 的正数:i &amp; 0b00111 % 0b0100

      7 % 4 = 3

      0111 (7)
      0011 (3) &
      -------
      0011 (3)
      

      【讨论】:

        【解决方案3】:

        发生这种情况是因为这些操作不同,所以你不会问为什么2+2 等于2*2,而是2+3 != 2*3,对吧?

        无论如何,主要问题是数字的按位表示不是1:1的关系,不同的数字可以有相同的表示(查看Signed versus Unsigned Integers。了解一些细节)

        所以,% 模运算符接受除法的余数并且它有符号,所以

        console.log(-100 % 256); // shows -100 which is true

        按位&amp; 与物理位一起工作,它不了解符号位的设置,因此,如果我们查看 -100 的按位表示 - 它是10011100,同时它是 156 的按位表示

        console.log((0b10011100)); // unsigned 156
        console.log((0b10011100 << 24 >> 24)); // signed -100

        【讨论】:

          猜你喜欢
          • 2012-01-16
          • 2018-01-11
          • 2011-10-15
          • 2011-07-27
          • 1970-01-01
          • 2017-02-15
          • 2023-04-10
          相关资源
          最近更新 更多