JavaScript 中的计算结果与 Java 中的计算结果不同

Different calculation outcome in JavaScript than in Java

本文关键字:计算 结果 JavaScript Java      更新时间:2023-09-26
我认为我有一个

大数字的问题。

Java中的计算:

int n = 4451 + 554 * 57;
n = n << 13 ^ n;
System.out.println(n * (n * n * 15731 + 789221) + 1376312589);
=> 587046333

在 JavaScript 中:

var n = 4451 + 554 * 57;
n = n << 13 ^ n;
console.log(n * (n * n * 15731 + 789221) + 1376312589);
=> 4.043454188561781e+29
JavaScript版本

有什么问题,我该如何解决它,以便JavaScript的结果与Java的结果相同?

编辑:尝试使用:https://github.com/jtobey/javascript-bignum,但结果为0

var test = new BigInteger(295120061).multiply( new BigInteger(295120061) 
                                      .multiply(new BigInteger(295120061)) 
                                      .multiply(new BigInteger(15731)) 
                                      .add(new BigInteger(789221)))
                                      .add(new BigInteger(1376312589));

=>测试 = 0

JavaScript 没有整数算术,所有数字都存储为 64 位浮点数(在 Java 中double)。 当 JavaScript 看到像 <<^ 这样的位处理运算符时,它会暂时将操作数转换为 32 位整数以执行算术运算,但随后将它们转换回 64 位浮点数。 因此,最后一个乘法在 JavaScript 中作为浮点运算执行。 在 Java 中,它仍然是一个整数操作。 这段代码在 Java 中执行相同的操作(我现在已经测试过了,结果是一样的):

int n = 4451 + 554 * 57;
n = n << 13 ^ n;
double x = n;
System.out.println(x * (x * x * 15731 + 789221) + 1376312589);

如果你想要与Java相同的JavaScript代码,你将需要一种方法来执行乘法和加法,其工作方式与Java在溢出时的工作方式相同。 也就是说,它必须将所有操作的结果视为在 -2 31 和 231-1 范围内。 在 JavaScript 中使用其原生算术确实没有可靠的方法来做到这一点;即使你给它两个只有 31 个有效位的值,当你将它们相乘时,你会得到 62 个有效位,而 JavaScript 的"数字"类型只有 52 位,这意味着一些位会丢失。 可能有一个JavaScript库可以让你做这种精确的整数算术,但我不是JavaScript框架的专家,所以我不知道那会是什么。 也许其他人会插话。

正如@ajb所说,问题在于 JavaScript 是松散类型的,并且执行双精度浮点运算,而我们需要严格的 32 位整数算术。

对于乘法,函数Math.imul为此目的而存在。Internet Explorer 尚不支持它,但链接页面包含一个替换函数,该函数模拟旧版浏览器的imul,该功能的工作原理是分别将数字的上半部分和下半部分相乘。

对于加法,我们可以用 0 或数字。这是有效的,因为任何按位操作都会强制 JavaScript 数字变成 32 位整数,而 0 的 ORing 实际上不会更改超出此值的值:

Math.iadd = function(a, b) { return ((a|0) + (b|0))|0; }

现在使用它:

var n = Math.iadd(4451, Math.imul(554, 57));
n = n << 13 ^ n;
console.log(Math.iadd(Math.imul(n, Math.iadd(Math.imul(Math.imul(n, n), 15731), 789221)), 1376312589));

有点长和凌乱,但它有效。输出是587046333的,与Java相同。

使用: https://github.com/iriscouch/bigdecimal.js

var n = 4451 + 554 * 57; 
n=n << 13 ^ n; 
var test = new BigDecimal(n).multiply( new BigDecimal(n) 
                                      .multiply(new BigDecimal(n)) 
                                      .multiply(new BigDecimal(15731)) 
                                      .add(new BigDecimal(789221)))
                                      .add(new BigDecimal(1376312589));
    test.intValue()

打印正确的结果