2011-06-03 66 views
6

有沒有辦法在JavaScript中正確乘以兩個32位整數?有沒有辦法在JavaScript中正確乘以兩個32位整數?

當我使用long long試試這個由C我得到這個:

printf("0x%llx * %d = %llx\n", 0x4d98ee96ULL, 1812433253, 
     0x4d98ee96ULL * 1812433253); 
==> 0x4d98ee96 * 1812433253 = 20becd7b431e672e 

但是從Javascript的結果是不同的:

x = 0x4d98ee97 * 1812433253; 
print("0x4d98ee97 * 1812433253 = " + x.toString(16)); 
==> 0x4d98ee97 * 1812433253 = 20becd7baf25f000 

的尾隨零使我懷疑,JavaScript有一個奇怪的有限整數分辨率介於32位和64位之間。

有沒有辦法得到正確答案? (我在x86_64 Fedora 15上使用Mozilla js-1.8.5以防萬一)

+2

供參考:它實際上是圍繞[53個比特](http://groups.google.com/group/twitter-api-announce/browse_thread/thread/6a16efa375532182?pli=1)。 – Thai 2011-06-04 03:31:25

+1

你可以使用[Math.imul](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul) – 2016-03-25 13:52:05

回答

9

這似乎做什麼,我想沒有外部的依賴:

function multiply_uint32(a, b) { 
    var ah = (a >> 16) & 0xffff, al = a & 0xffff; 
    var bh = (b >> 16) & 0xffff, bl = b & 0xffff; 
    var high = ((ah * bl) + (al * bh)) & 0xffff; 
    return ((high << 16)>>>0) + (al * bl); 
} 

此執行32位乘法模2^32,這是計算的正確的下半部分。一個類似的函數可以用來計算一個正確的上半部分並將其存儲在一個單獨的整數中(ah * bh似乎是正確的),但我並不需要這樣做。

注意零漂。沒有這個功能,當高位被設置時,該函數會產生負值。

+1

如果我運行'multiply_uint32(0xffffffff,0xffffffff)',則返回'0x100000001'。我想你的意思是在整個返回值之後再做一次'&0xffffffff'。 – 2014-06-27 01:01:26

3

你是正確的。 Javascript整數被視爲浮點數,在處理整數時精度較差。

在JavaScript中,它是10000000000000001%2 == 0

一個朋友也提到10000000000000001 == 10000000000000000的情況,這確實是由於規範(雖然整數用於優化,該規範還要求浮動類似的行爲) 。

雖然一旦你在這個領域,你已經接近64位整數精度的極限了。

+1

因爲整數實際上被存儲爲IEEE 754雙精度值,精度(64位)浮點數,你不可能比54(或53類似於這樣)的精度更好,但是在JavaScript需要做int類似的事情(數組索引)時,它會下降到31位無論如何。 – Pointy 2011-06-03 22:22:16

0

GWT模擬Java(64位)帶符號長整數類型。我爲它製作了一個JavaScript界面​​,here's a demo。使用默認數字,您可以看到該值與您在C中獲得的值相同。

「仿真」列中的十六進制值應與您在調試器中看到的一致,但可能會有由於我使用原生JavaScript來創建它,所以在十六進制表示方面存在問題。它當然也可以在GWT中完成,這可能會使它更加正確。如果JavaScript Number可以表示GWT生成的所有字符串表示形式,則十六進制表示形式也應該是正確的。查看使用情況的來源。他們({sub,mod,div,mul} ss)帶字符串的原因是因爲我不知道如何使用JavaScript創建GWT Long對象。

4

a forum post

沒有必要做數字小,只 事項保持顯著的位數低於53

function mult32s(n, m) //signed version 
{ 
    n |= 0; 
    m |= 0; 
    var nlo = n & 0xffff; 
    var nhi = n - nlo; 
    return ((nhi * m | 0) + (nlo * m)) | 0; 
} 

function mult32u(n, m) //unsigned version 
{ 
    n >>>= 0; 
    m >>>= 0; 
    var nlo = n & 0xffff; 
    var nhi = n - nlo; 
    return ((nhi * m >>> 0) + (nlo * m)) >>> 0; 
} 

兩個|>>>運營商造成結果被轉換爲32位整數。在第一種情況下,它被轉換爲有符號整數,在第二種情況下,它被轉換爲無符號整數。

在乘法的行的第一個|/>>>操作者使與48位有效(格式0x NNNN NNNN NNNN 0000)放棄其較高位的64位的中間結果,所以中間結果是在表格0x NNNN 0000
第二個|/>>>運算符使第二乘法和加法的結果限制爲32位。

萬一被乘數之一是一個常數可以簡化乘法進一步:

function mult32s_with_constant(m) //signed version 
{ 
    m |= 0 
    //var n = 0x12345678; 
    var nlo = 0x00005678; 
    var nhi = 0x12340000; 
    return ((nhi * m | 0) + (nlo * m)) | 0; 
} 

或者,如果你知道的結果將是小於53位,那麼你可以這樣做:

function mult32s(n, m) //signed version 
{ 
    n |= 0; 
    m |= 0; 
    return (n * m) | 0; 
} 
相關問題