简体   繁体   English

哈克将javascript编号转换为UInt32

[英]Hack to convert javascript number to UInt32

Edit: This question is out of date as the Polyfill example has been updated. 编辑:此问题已过期,因为Polyfill示例已更新。 I'm leaving the question here just for reference. 我在这里留下这个问题仅供参考。 Read the correct answer for useful information on bitwise shift operators. 阅读关于按位移位运算符的有用信息的正确答案。


Question: 题:

On line 7 in the Polyfill example of the Mozilla Array.prototype.indexOf page they comment this: 在Mozilla Array.prototype.indexOf页面的Polyfill示例中的第7行,他们对此进行评论:

var length = this.length >>> 0; // Hack to convert object.length to a UInt32

But the bitwise shift specification on Mozilla clearly states that the operator returns a value of the same type as the left operand: 但Mozilla上的按位移位规范明确指出运算符返回与左操作数相同类型的值:

Shift operators convert their operands to thirty-two-bit integers and return a result of the same type as the left operand. 移位运算符将其操作数转换为32位整数,并返回与左操作数相同类型的结果。

So shouldn't length receive the standard 64-bit float value? 所以不应该长度接收标准的64位浮点值? Or can someone point out to me where the hack starts? 或者有人能指出我黑客入手的地方?

The ECMAScript specification states that the value is converted to UInt32 in step 5 and 8 of http://www.ecma-international.org/ecma-262/5.1/#sec-11.7 : ECMAScript规范声明该值在http://www.ecma-international.org/ecma-262/5.1/#sec-11.7的步骤5和8中转换为UInt32:

11.7.3 The Unsigned Right Shift Operator ( >>> ) 11.7.3无符号右移运算符(>>>)

Performs a zero-filling bitwise right shift operation on the left operand by the amount > specified by the right operand. 对左操作数执行零填充按位右移操作,操作数由右操作数指定。

The production ShiftExpression : ShiftExpression >>> AdditiveExpression is evaluated as follows: 生产ShiftExpression : ShiftExpression >>> AdditiveExpression的计算方法如下:

  1. Let lref be the result of evaluating ShiftExpression . lref成为评估ShiftExpression的结果。
  2. Let lval be GetValue(lref) . lvalGetValue(lref)
  3. Let rref be the result of evaluating AdditiveExpression . rref成为评估AdditiveExpression的结果。
  4. Let rval be GetValue(rref) . rvalGetValue(rref)
  5. Let lnum be ToUint32(lval) . lnum成为ToUint32(lval)
  6. Let rnum be ToUint32(rval) . rnum成为ToUint32(rval)
  7. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum , that is, compute rnum & 0x1F . shiftCount是屏蔽除rnum的最低有效5位之外的所有位的rnum ,即计算rnum & 0x1F
  8. Return the result of performing a zero-filling right shift of lnum by shiftCount bits. 返回通过shiftCount位执行lnum的零填充右移的结果。 Vacated bits are filled with zero. 空位用零填充。 The result is an unsigned 32-bit integer . 结果是无符号的32位整数

The result is, indeed, converted back to a number, ie, a 64-bit precision floating point number. 实际上,结果被转换回一个数字,即64位精度浮点数。 However, before it is converted back, both operands are converted to UInt32 , then the right shift operation is performed. 但是,在转换回来之前,两个操作数都转换为UInt32 ,然后执行右移操作。 This is specified in ECMAScript here: http://www.ecma-international.org/ecma-262/5.1/#sec-11.7.3 这在ECMAScript中有详细说明: http//www.ecma-international.org/ecma-262/5.1/#sec-11.7.3

The net result of length >>> 0 is therefore, because >>> 0 itself is a no-op, to convert length to a UInt32 then back to a double. 因此, length >>> 0的净结果是因为>>> 0本身是无操作,将length转换为UInt32然后再转换为双UInt32 What is it good for? 到底有什么好处呢? It forces the loss of precision, and effectively forces the value to be 1) and integer and 2) in the range [0, 2^32-1]. 它会强制精度损失,并有效地强制值为1),整数和2)在[0,2 ^ 32-1]范围内。 For example, if it was -1, it will become 2^32-1 == 4294967295. If it was, 3.6, it will become 3. 例如,如果它是-1,它将变为2 ^ 32-1 == 4294967295。如果是,3.6,它将变为3。

If you run this test, Math.floor will do the same. 如果您运行此测试,Math.floor将执行相同的操作。 Those hacks should be avoided if you want to understand your own code in a month or so. 如果您想在一个月左右的时间内了解自己的代码,就应该避免这些黑客攻击。

var a=3.6, b = a >>> 0;
console.log(b);
console.log(Math.floor(a));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM