2010-08-06 47 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