JavaScript Integer数学结果不正确

JavaScript Integer math incorrect results

我只是想在JS中实现一个简单的RNG。

正在发生的事情是javascript将119106029 * 1103515245评估为131435318772912110而不是131435318772912105。我们知道这是错误的,因为两个奇数相乘不会得到偶数。

有人知道怎么回事吗?我只想要一个可靠的可重复RNG,并且由于这些不正确的值,我无法获得与我的C实现相同的结果相匹配的结果。


根据ECMAScript标准,默认情况下,JavaScript中的所有数字均为(64位IEEE 754)浮点数。

但是,所有32位整数都可以精确地表示为浮点数。您可以使用适当的按位运算符将结果强制为32位,如下所示:

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

很奇怪,但这是标准。

(顺便说一下,这种四舍五入行为是针对Firefox JavaScript引擎的最常报告的"错误"之一。看起来到目前为止,今年已被报道3次……)

如果需要实整数运算,则可以使用BigInt值,这是另一种数字类型,其末尾用n编写:

1
2
> 119106029n * 1103515245n
131435318772912105n

这是一个相对较新的JS功能,可能无法在旧的浏览器中实现。

对于JavaScript中可重现的随机数,V8基准测试使用以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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;
  };
})();


当javascript中的整数太大而无法容纳32位值时,某些浏览器会将其转换为浮点数。由于仅将浮点值保存到有限的精度中,因此对大值可能会进行一些舍入。


随着BigInt的到来,您现在可以准确地执行以下计算:

1
console.log((119106029n * 1103515245n).toString());


如果以C / C(双精度)格式完成,则最后一个数字将为... 112
而不是105(正确)。如果执行"长双倍"
结果将与预期的一样(... 105)。所以看起来像
Javascript解释器将数字转换为8字节双精度数
在内部进行计算并进行一些未知的舍入
这导致比C / C标准略胜一筹的结果
双重计算。

GCC 4.5:

1
2
3
4
5
6
7
8
9
10
 int main(int argc, char** argv)
{
 long double a = 119106029;
 long double b = 1103515245;
 long double c = a * b;
 printf("%.Lf\
"
, c);

 return 0;
}

结果:

1
131435318772912105

预期:

1
131435318772912105

因此,如果没有
BIGNUM库的帮助(如果有)。

致谢

rbo