【问题标题】:Hack to convert javascript number to UInt32破解将 javascript 数字转换为 UInt32
【发布时间】:2014-03-11 20:24:24
【问题描述】:

编辑:此问题已过时,因为 Polyfill 示例已更新。我将问题留在这里仅供参考。阅读正确答案,了解有关按位移位运算符的有用信息。


问题:

在 Mozilla Array.prototype.indexOf 页面的 Polyfill 示例的第 7 行,他们对此发表了评论:

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

但是 Mozilla 上的 bitwise shift 规范明确指出,运算符返回与左操作数相同类型的值:

移位运算符将其操作数转换为 32 位整数,并返回与左操作数相同类型的结果。

那么 length 不应该接收标准的 64 位浮点值吗?或者有人可以向我指出黑客从哪里开始?

【问题讨论】:

    标签: javascript bit-manipulation operator-keyword indexof uint32


    【解决方案1】:

    ECMAScript 规范规定在http://www.ecma-international.org/ecma-262/5.1/#sec-11.7 的第 5 步和第 8 步中将值转换为 UInt32:

    11.7.3 无符号右移运算符 ( >>> )

    对左操作数按右操作数指定的量执行零填充按位右移操作。

    产生式ShiftExpression : ShiftExpression >>> AdditiveExpression 评估如下:

    1. lref 成为评估ShiftExpression 的结果。
    2. lval 成为GetValue(lref)
    3. rref 成为评估AdditiveExpression 的结果。
    4. rval 成为GetValue(rref)
    5. lnum 成为ToUint32(lval)
    6. rnum 成为ToUint32(rval)
    7. shiftCount 成为屏蔽除rnum 的最低有效5 位之外的所有结果,即计算rnum & 0x1F
    8. 返回对lnum 执行零填充右移shiftCount 位的结果。空出的位用零填充。 结果是一个无符号的 32 位整数

    【讨论】:

    • 感谢您的查找和参考规范的要点。这也意味着我帖子中链接的 Mozilla 参考指南对位运算符是错误的。
    • TLDR; var uint32 = num >>> 0
    【解决方案2】:

    实际上,结果被转换回一个数字,即一个 64 位精度的浮点数。但是,在转换回来之前,两个操作数都转换为UInt32,然后进行右移操作。这在 ECMAScript 中指定: http://www.ecma-international.org/ecma-262/5.1/#sec-11.7.3

    因此,length >>> 0 的最终结果是,因为>>> 0 本身是空操作,所以将length 转换为UInt32,然后再转换为双精度。到底有什么好处呢?它强制损失精度,并有效地将值强制为 1) 和整数和 2) 在 [0, 2^32-1] 范围内。例如,如果是-1,它将变为2^32-1 == 4294967295。如果是,3.6,它将变为3。

    【讨论】:

    • 这正是我的想法。我认为他们确实将其用作将精度降低到整数的捷径。但我仍然不明白为什么他们会包含这样的黑客。我假设目前还有更多内容(Mozilla 的聪明人)
    【解决方案3】:

    如果您运行此测试,Math.floor 将执行相同的操作。如果您想在一个月左右的时间内了解自己的代码,则应该避免这些黑客攻击。

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

    【讨论】:

    • 如果您查看 Math.floor (ecma-international.org/ecma-262/5.1/#sec-15.8.2.9) 的规范并将其与按位移位运算符进行比较,您会发现 Math.floor 不涉及更改数字值的内部表示从 64 位浮点到有符号或无符号 32 位整数表示。如果它在你想要的小数点之外失去精度,那么你就误读了这个问题。
    猜你喜欢
    • 2015-06-06
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 2011-09-23
    相关资源
    最近更新 更多