2013-03-22 92 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位整數。
相關問題