javascript-如何在jjs / Nashorn中使用java.math.BigInteger?

我想在nashorn / jss JavaScript中使用java.math.BigInteger.

举例来说,假设我要计算斐波那契数列.即使数字很大,数字也必须保持准确.

可用的Java代码如下所示:

public static BigInteger fibonacci(int n) {
  BigInteger prev = new BigInteger("0");
  if (n == 0) return prev;

  BigInteger next = new BigInteger("1");
  if (n == 1) return next;

  BigInteger fib = null;
  int i;
  for (i = 1; i < n; i++) {
    fib = prev.add(next);
    prev = next;
    next = fib;
  }
  return fib;
}

我们可以测试:

> n = 77:5527939700884757
> n = 78:8944394323791464
> n = 79:14472334024676221

到现在为止还挺好.

等效的JavaScript代码如下:

function fibonacci(n) {
  var BigInteger = Java.type("java.math.BigInteger");
  prev = new BigInteger("0");
  if (n == 0) return prev;

  next = new BigInteger("1");
  if (n == 1) return next;

  var i, fib = null;
  for (i = 1; i < n; i++) {
    fib = prev.add(next);
    prev = next;
    next = fib;
  }
  return fib;
}

现在我们得到:

> n = 77:5527939700884757
> n = 78:8944394323791464
> n = 79:14472334024676220

请注意,79的值是一个off-是错误的.

我怀疑问题是在某个地方,BigNumber值被重新解释为普通的JavaScript数字. (由于“ Bigwhere”被传递给.add方法,我怀疑这已经发生了)

例如,如果我这样做:

var BigInteger = Java.type("java.math.BigInteger");
print(new BigInteger("14472334024676221"));

输出是14472334024676220,而不是14472334024676221.
即使我在BigInteger对象上显式调用.toString(),也会发生这种情况.

我该如何克服?

更新:@Dici问我是否在寻找阈值.我做到了-我发现:

var str, BigInteger = Java.type("java.math.BigInteger");
str = "9999999999999998";
print(str + ": " + new BigInteger(str));
str = "9999999999999999";
print(str + ": " + new BigInteger(str));

将输出:

> 9999999999999998:9999999999999998
> 9999999999999999:10000000000000000

我不确定这是“门槛”问题,还是某些不准确的数字.

更新2:

现在报告为错误:https://bugs.openjdk.java.net/browse/JDK-8146264
错误报告是由Oracle JDK / Nashorn开发人员完成的,因此我认为这是真实的.保持我的手指交叉.

最佳答案
是的,这是一个问题.已提交错误-> https://bugs.openjdk.java.net/browse/JDK-8146264

JSType和其他几个地方都进行了“ instanceof Number”检查-不知道单独修复JSType.toStringImpl是否可以.无论如何,我都有一个解决方法-不是一个很漂亮的方法-但还是有一个解决方法.您可以在这些对象上调用java.lang.Object.toString方法,从而避免使用Nashorn的JSType字符串转换代码.

function fibonacci(n) {
  var BigInteger = Java.type("java.math.BigInteger");
  prev = new BigInteger("0");
  if (n == 0) return prev;

  next = new BigInteger("1");
  if (n == 1) return next;

  var i, fib = null;
  for (i = 1; i < n; i++) {
    fib = prev.add(next);
    prev = next;
    next = fib;
  }
  return fib;
}

function javaToString(obj) {
    var javaToStringMethod = (new java.lang.Object()).toString;
    var call = Function.prototype.call;
    return call.call(javaToStringMethod, obj);
}

print(javaToString(fibonacci(77)))
print(javaToString(fibonacci(78)))
print(javaToString(fibonacci(79)))

var str, BigInteger = Java.type("java.math.BigInteger");
str = "9999999999999998";
print(str + ": " + javaToString(new BigInteger(str)));
str = "9999999999999999";
print(str + ": " + javaToString(new BigInteger(str)));

转载注明原文:javascript-如何在jjs / Nashorn中使用java.math.BigInteger? - 代码日志