我想在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数字。 (通过“某处”,我怀疑这已经发生了,因为所谓的BigInteger传递给了.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?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34502968/

    10-10 19:27