按位运算 - 无符号右移零填充(>>>)的用途?

9

一般来说,位移运算(>> , <<)允许我们通过左移或右移操作实现除以或乘以2的幂次方。

例如:

      9 (base 10): 00000000000000000000000000001001 (base 2)
                   --------------------------------
 9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)

对于负数

同样地,-9 >> 2 的结果为 -3,因为符号被保留:

     -9 (base 10): 11111111111111111111111111110111 (base 2)
                   --------------------------------
-9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)

然而,观察 >>> 的行为,在正数时它的表现相同,但在负数时的行为不同:

MDN

从左侧开始,零 位被移入。

我找不到任何理由或用途来自左侧进行 0 移位(这将使整个数字为正数):

       -9 (base 10): 11111111111111111111111111110111 (base 2)
                     --------------------------------
 -9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)

问题:

在什么情况下我应该使用>>>?我不明白为什么我会想要从左侧填充零并弄乱我的负数。

回答:

>>>是Python中的逻辑右移运算符。它将二进制数向右移动,并用0填充左侧,而不是使用符号位扩展(即保持最高位不变)。这意味着如果您需要将正数除以2的幂次方,则可以使用逻辑右移。但是,如果您需要处理负数,则应使用算术右移(使用符号位扩展)。


1
阅读逻辑右移,>>>运算符>>保留符号,但>>>不会。 - Grijesh Chauhan
@GrijeshChauhan 这真的很有帮助,但它只解释了它的工作原理,而我已经知道了。但在什么情况下应该使用它?我没有看到任何移位这些位向右移动并添加左填充零的数学运算。我的意思是,如果我让你使用位运算符除以一个数字,你会选择 >>,但是你什么时候会选择 >>> 呢? - Royi Namir
好的,我再次阅读了您的问题。我在某个地方读到无符号移位在图形编程中经常使用。我不知道具体是怎么用的。所以 +。 - Grijesh Chauhan
阅读:阅读使用>>>有时我们在编程中使用,例如我在我的回答中使用了它。 - Grijesh Chauhan
1
@RoyiNamir 这取决于你如何读取(解释)11111111111111111111111111110111。我可能想要将其作为无符号整数 0xfffffff7 使用,并进行右移以除以它。 - L.B
显示剩余5条评论
2个回答

6
一个简单而常见的用例是将变量转换为32位无符号整数(UInt32)。当您执行变量 >>> 0时,如果该变量已经是UInt32,则保持不变,否则为0。例如:

enter image description here

使用示例:

function convert( arrayLikeVariable){
   // we dont know for sure if length is UInt32
   // e.g. arrayLikeVariable.length = "zavarakatranemia"
   // so we do >>> 0
   var len = arrayLikeVariable >>> 0 
   // Now len is UInt32 for sure. 
   [..]
   // code using the len
}

如果您需要一个完整的示例,请查看此处的Polyfill:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf


if (!Array.prototype.indexOf)  Array.prototype.indexOf = (function(Object, max, min){
  "use strict";
  return function indexOf(member, fromIndex) {
    if(this===null||this===undefined)throw TypeError("Array.prototype.indexOf called on null or undefined");

    var that = Object(this), Len = that.length >>> 0, i = min(fromIndex | 0, Len);
    if (i < 0) i = max(0, Len+i); else if (i >= Len) return -1;

    if(member===void 0){ for(; i !== Len; ++i) if(that[i]===void 0 && i in that) return i; // undefined
    }else if(member !== member){   for(; i !== Len; ++i) if(that[i] !== that[i]) return i; // NaN
    }else                           for(; i !== Len; ++i) if(that[i] === member) return i; // all else

    return -1; // if the value was not found, then return -1
  };
})(Object, Math.max, Math.min);

5

假设你正在编写一个模拟硬件的程序,具体来说是一个移位寄存器

为了简化问题,我将使用8位而不是你问题中的32位。

每次我们想要输入高位到这个移位寄存器时,我们可以加上128,因为它会使最左边的位变为1。

// Assume n is initialised to 0, so n = 00000000 in binary
n += 128;                    // now n = 10000000 in binary

如果每次想模拟一个时钟周期都使用 >>> 进行移位,那么在 8 个“时钟周期”后,我们将在最右边的位上得到 1。如果我们读取该最右边的位,那么我们将得到输入到最左边位 8 个周期之前的延迟版本。
这只是一个例子,其中比特不被解释为数字,我相信还有很多类似的用途。我认为你会在其他地方找到更多用途,尤其是在旨在模拟硬件电路/构建块的软件中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接