2013-03-22 54 views
3

我正在使用此代码来试图找出数字中有多少位。下面的十六进制数字打开所有位。这个代码为什么给一个数字(而不是53)的位给32?

for (var i = 0x1FFFFFFFFFFFFF, m = 0; i & 1; ++m, i >>>= 1); 

出于某种原因,打印m给32,但在SO后我阅读以下内容:

在JavaScript中所有的数字实际上是IEEE-754标准的浮点双打。这些都有一个53位的尾数,这应该意味着任何大小约为9千兆或更小的整数值都将被精确表示。

除非我错误地实现这一点,否则我不明白为什么打印m应该给出32时应该有53位。有人可以解释吗?

+0

我没有看到你的代码完成了什么。即使这对任意大小的数字都有效,如果你的'i'是一个像'111 ... 1110'这样的二进制表示的东西,你最终会得到'm = 0' – NullUserException 2013-03-22 00:11:38

+0

@NullUserException这是怎么回事? – 2013-03-22 00:13:00

+0

二进制表示中的任何0都会导致循环立即中止。所以如果你的二进制文件以0结尾,循环以第一次迭代结束。 – NullUserException 2013-03-22 00:15:17

回答

6

按位操作由JavaScript/ECMAScript标准截断号指定到31位(向零舍入,取模数为2,将最高有效位解释为二进制补码),然后再发生任何其他事情。所以你需要用普通算术重新编码它。

这部分是因为处理分数的FPU可能无法在逻辑电路级执行按位操作。

最天真的测试方式是for (var i = 0; i != i + 1; ++ i) ;,但是当我尝试它时,它崩溃了。 (期待超时,但没了!)稍微更具体的单行

for (var i = 1, j = 0; i != i + 1; i *= 2, ++ j) ; 

不会产生j == 53

顺便说一句,请注意,用于舍入的成语x | 0不适用于大于或等于2的数字。所以Math.round通常更好。

+0

我喜欢你的答案,因为你解释了好处:通过避免FPU未提供的功能来提高性能。 – dsh 2013-03-22 00:10:02

+1

@dsh JavaScript是否在任何性能关键的应用程序中使用? – NullUserException 2013-03-22 00:13:54

+0

@NullUserException我看到了一些情况,但在这些情况下,通常使用像NACL或asm.js这样的东西。在本地JavaScript中,人们通常在需要更多'整数'操作时使用键入的UInt数组。 – 2013-03-22 00:16:39

5

按位操作为>>>工作在32位数,所以i实际上转换为32位。有关更多信息,请参阅this

speficication

生产ShiftExpression:

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

  1. 让LREF:ShiftExpression >>> AdditiveExpression如下评价是评估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. 返回通过shiftCount位执行lnum的零填充右移的结果。空位填充零。结果是一个无符号的32位整数。
相关问题