JavaScript Integer math incorrect results
我只是想在JS中实现一个简单的RNG。
正在发生的事情是javascript将
有人知道怎么回事吗?我只想要一个可靠的可重复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次……)
如果需要实整数运算,则可以使用
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