Why is the eval class giving me a casting error from int to double?

泄露秘密 提交于 2019-12-02 06:24:54

Nashorn uses optimistic typing (since JDK 8u40), so it will using integers when doubles are not needed. Thus, you cannot count on it returning a Double.

Also, 5*x^2 means "five times x xor two" in JavaScript. The ** exponentiation operator is defined in newer versions of the JavaScript language, but Nashorn doesn't support it yet.

If you change your JavaScript code to 5*x*x it will work, but it would be safer to do:

total += 0.001 * ((Number)engine.eval(function)).doubleValue();

Compiling Frequently Used Code

Since you call this function repeatedly in a loop, a best practice is to compile the function in advance. This performance optimization is not strictly necessary, but as it is the engine has to compile your function every time (although it may use a cache to help with that).

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;

CompiledScript compiledScript = ((Compilable)engine)
    .compile("function func(x) { return " + function + "}");
compiledScript.eval(compiledScript.getEngine()
    .getBindings(ScriptContext.ENGINE_SCOPE));

Invocable funcEngine = (Invocable) compiledScript.getEngine();

// . . .

total += 0.001 * ((Number)funcEngine.invokeFunction("func", i)).doubleValue();

Using ES6 Language Features

In the future, when Nashorn does support the ** operator, if you want to use it you may need to turn on ES6 features like this:

import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine enjin = factory.getScriptEngine("--language=es6");

Or like this:

java -Dnashorn.args=--language=es6

* Edited to account for the mathematical fix pointed out in the comments.

Your JS snippet returns an Integer (*), because x^2 is not the correct way to get a power of 2 in JavaScript. Try 5*Math.pow(x,2) instead, and the expression will return a Double.

In JavaScript, ^ operator is bitwise XOR.

Also the loop to compute the integral is wrong, you need to multiply by rectangle width:

    double delta = 0.001;
    for (double i = lower; i < upper; i += delta) {
        //evaluates the interval
        engine.put("x", i);
        total += delta * ((Number) engine.eval(function)).doubleValue();
    }

(*) See David's answer for a tentative explanation. But in comments, @A.Sundararajan provides evidence against this. I have not investigated the exact reason, I have only observed I got an Integer, and was only guessing the use of bitwise operation in expression (from OP's original code) was triggering a conversion to integer. I originally edited my post to include the fix for "math error", but David's newer answer (by about 4 minutes ^^) is more complete for the original question, and should remain the accepted answer IMHO.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!