2010-08-06 125 views
3

我只是試圖在JS中實現一個簡單的RNG。JavaScript整數數學錯誤結果

發生了什麼事是javascript評估119106029 * 1103515245131435318772912110而不是131435318772912105。我們知道這是錯誤的,因爲兩個奇數相乘並不能給出偶數。

任何人都知道這是怎麼回事?我只想要一個可靠的可重複RNG,並且由於這些不正確的值,我無法得到與我的C實現相同的結果。

+0

如果我是你,我會問:爲什麼你需要擺在首位乘這樣龐大的數字?如果不使用這種方法,這可能是一種做你想做的事的方法。 除非它的一些科學問題領域,你可能會有設計錯誤。 – Nobody 2010-08-06 22:12:09

+0

只是製作最簡單的隨機數發生器。大數乘以2 ** 32加一個常數mod。我只對最後幾位感興趣!但他們錯了。爲什麼? – 2010-08-06 22:13:34

+3

'Math.random()* 100000(00 .....)'是不夠的時候!? – Matt 2010-08-06 22:16:38

回答

17

根據ECMAScript標準,JavaScript中的所有數字都是(64位IEEE 754)浮點數。

但是,所有32位整數都可以精確地表示爲浮點數。您可以使用適當的按位運算符將結果強制爲32位,如下所示:

x = (a * b) >>> 0; // force to unsigned int32 
x = (a * b) | 0; // force to signed int32 

奇怪,但這是標準。

(順便說一句該舍入行爲是one of the most frequently reported "bugs"針對Firefox的JavaScript引擎看起來像它今年已報告3次,到目前爲止...)

至於在JavaScript可重複的隨機數,在V8基準測試使用此:

// To make the benchmark results predictable, we replace Math.random 
// with a 100% deterministic alternative. 
Math.random = (function() { 
    var seed = 49734321; 
    return function() { 
    // Robert Jenkins' 32 bit integer hash function. 
    seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; 
    seed = ((seed^0xc761c23c)^(seed >>> 19)) & 0xffffffff; 
    seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; 
    seed = ((seed + 0xd3a2646c)^(seed << 9)) & 0xffffffff; 
    seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; 
    seed = ((seed^0xb55a4f09)^(seed >>> 16)) & 0xffffffff; 
    return (seed & 0xfffffff)/0x10000000; 
    }; 
})(); 
+0

IIRC我在我的應用程序([htmltetris.com](http://htmltetris.com))中使用了這個或者Robert Jenkins PRNG的其他變體 – 2014-07-15 15:12:54

3

當javascript中的整數太大而不適合32位值時,某些瀏覽器會將其轉換爲浮點。由於浮點的值只能保存到有限的精度,所以在大值時可能會出現一些舍入。

+0

儘管結果對於最後兩位是正確的。如果它只是截斷高位,但我想要的只是結果的低32位,這是有道理的。我如何獲得? – 2010-08-06 22:10:29

+0

@Steven:Javascript實際上並沒有整數類型,在這種情況下,您會看到浮點數的精度損失。而那些保留數字的「上半部分」,而不是低位(像整數乘法那樣)。 – Joey 2010-08-06 22:12:14

+0

@Johannes:好的,這很有道理。不知道如何解決這個問題... – 2010-08-06 22:15:01

1

如果在C/C++(雙)中完成,最後的數字將是... 112 而不是105(這是正確的)。如果執行'長雙', 結果將如預期的那樣(... 105)。所以它看起來像是 Javascript解釋器在內部將數字轉換爲8字節雙倍的 ,進行計算並做了一些未知的取整 ,這導致比C/C++標準 雙重計算稍微好一點的結果。

GCC 4.5:

int main(int argc, char** argv) 
{ 
long double a = 119106029; 
long double b = 1103515245; 
long double c = a * b; 
printf("%.Lf\n", c); 

return 0; 
} 

結果:

131435318772912105 

預計:

131435318772912105 

所以我看不出在Javascript的機會,而不 援助BIGNUM庫(如果有的話)。

問候

RBO