如何在jjs/Nashorn中使用java.math.BigInteger
How to use java.math.BigInteger in jjs / Nashorn?
我想在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:144772334024676221
到目前为止还不错。
以下等效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:144772334024676220
请注意,79的值是一次性的,这是错误的。
我怀疑问题在于,在某些地方,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));
将输出:
- 99999999999 8:999999999999999 8
- 9999999999999999:10000000000000000
我不确定这是"非法侵入"的问题,或者某些特定的数字有不准确之处。
更新2:
现在报告为一个错误:https://bugs.openjdk.java.net/browse/JDK-8146264Bug报告是由Oracle JDK/Nashorn开发人员完成的,所以我想这是真实的。祈祷吧。
是的,这是一个问题。已提交错误->https://bugs.openjdk.java.net/browse/JDK-8146264
JSType和其他一些地方都有"instanceofNumber"检查——不确定单独修复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)));
我举了你的例子:
var BigInteger = Java.type("java.math.BigInteger");
print(new BigInteger("14472334024676221"));
在调试模式下启动程序,注意到没有使用BigInteger
的toString
方法。所以我创建了一个简单的类:
public class ToString {
private final BigInteger x;
public ToString(BigInteger x) {
this.x = x;
}
@Override
public String toString() {
return x.toString();
}
}
并使用它来输出BigInteger
,它起到了作用:
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineManager.getEngineFactories().get(0).getScriptEngine();
String script = "var BigInteger = Java.type('"java.math.BigInteger'");'n" +
"var ToString = Java.type('"com.stackoverflow.inner.ToString'");'n" +
"var ts = new ToString(new BigInteger('"14472334024676221'"));'n" +
"print(ts);";
jsEngine.eval(script); // prints 14472334024676221
然后我怀疑Nashorn在将BigInteger
转换为String
之前使用了一些中间转换,所以我在BigInteger.doubleValue()
处创建了一个断点,并在打印裸BigInteger
时触发。以下是有问题的堆栈跟踪,让您了解Nashorn的逻辑:
at java.math.BigInteger.doubleValue(BigInteger.java:3888)
at jdk.nashorn.internal.runtime.JSType.toStringImpl(JSType.java:976)
at jdk.nashorn.internal.runtime.JSType.toString(JSType.java:327)
at jdk.nashorn.internal.runtime.JSType.toCharSequence(JSType.java:341)
at jdk.nashorn.internal.objects.NativeString.constructor(NativeString.java:1140)
以及有问题的Nashorn代码JSType.toStringImpl
:
if (obj instanceof Number) {
return toString(((Number)obj).doubleValue());
}
- 将jsp文件下拉列表中的选定项分配给一个java变量(比如String selection)
- 借助asp.net验证或java脚本对多个文本进行验证
- java.net和javascript之间正则表达式的差异
- 如何从Java/scala调用js美化程序
- 如何使用json将对象列表从java转换为javascript
- Java脚本时间添加
- WebDriverException:tinyMCE未在selenium Web driver java中定义
- 如何将字符串值从php页面发送到java脚本页面
- 如何使用Spring MVC将Facebook返回的响应数据保存在Java类中
- 如何轻松地将服务器端变量从Java代码转移到客户端代码
- DOM事件通过JSON转换为java
- 在 Java 中的 JavaScript 函数中插入 Wicket 值
- JSON分析错误:Java中AJAX、Javascript和Servlet的意外EOF
- java脚本在Chrome和其他浏览器中对LocaleTimeString的不同行为
- 错误405:向Java控制器(Ajax)发送JSON时找不到POST方法
- Java-彩票统计解析器
- 为什么Java和Javascript Math.round(-1.5)到-1
- Java脚本中的Math.max函数
- Java - ScriptEngineManager nashorn Math.random 不起作用
- 如何在jjs/Nashorn中使用java.math.BigInteger