JavaScript 整数数学结果不正确

发布于 2024-09-13 10:02:28 字数 256 浏览 3 评论 0原文

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

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

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

I am just trying to implement a simple RNG in JS.

What's happening is javascript evaluates 119106029 * 1103515245 to be 131435318772912110 rather than 131435318772912105. We know it's wrong since two odd numbers multiplied does not give an even number.

Anyone know what's up? I just want a reliable repeatable RNG, and because of these incorrect values I can't get results to match up with my C implementation of the same thing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

戏舞 2024-09-20 10:02:28

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

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

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

很奇怪,但这就是标准。

(顺便说一句,这种舍入行为是最常报告的“错误”之一 Firefox 的 JavaScript 引擎今年到目前为止已被报道 3 次...)

如果您想要真正的整数数学,您可以使用 BigInt 值,这是一种不同类型的数字,用 编写>n 结尾:

> 119106029n * 1103515245n
131435318772912105n

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


至于 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;
  };
})();

Per the ECMAScript standard, all numbers in JavaScript are (64-bit IEEE 754) floating-point numbers by default.

However all 32-bit integers can be exactly represented as floating-point numbers. You can force a result to 32 bits by using the appropriate bitwise operator, like this:

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

Weird, but that's the standard.

(Incidentally this rounding behavior is one of the most frequently reported "bugs" against Firefox's JavaScript engine. Looks like it's been reported 3 times so far this year...)

If you want real integer math, you can use BigInt values, a different type of number, written with an n at the end:

> 119106029n * 1103515245n
131435318772912105n

This is a relatively recent JS feature, and may not be implemented in old browsers.


As for reproducible random numbers in JavaScript, the V8 benchmark uses this:

// 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;
  };
})();
三生殊途 2024-09-20 10:02:28

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

When an integer in javascript is too big to fit in a 32 bit value, some browsers will convert it to a floating point. Since the value of floating points is only save to a limited precision, some rounding can occur on big values.

单身情人 2024-09-20 10:02:28

如果在 C/C++(双精度)中完成,最后的数字将是 ...112
而不是 105(这是正确的)。如果使用“long double”执行,
结果将如预期(...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

所以如果没有
BIGNUM 库的帮助(如果有)。

问候

rbo

If done in C/C++ (double), the last numbers will be ...112
instead of 105 (which is correct). If performed with 'long double',
the result will be as expected (...105). So it looks like the
Javascript interpreter converts the numbers to 8-byte-double
internally, does the calculation and does some unknown rounding
which leads to a marginally better result than the C/C++ standard
double calculation.

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;
}

Result:

131435318772912105

Expected:

131435318772912105

So I don't see a chance in Javascript without the
aid of a BIGNUM library (if any).

Regards

rbo

你是我的挚爱i 2024-09-20 10:02:28

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

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

With the arrival of BigInt, you can now perform these calculations with accuracy:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文