Java - 用户输入数学函数的高效评估(准备可能,现有变量)
Java - Efficient evaluation of user-input math functions (preparation possible, existing variables)
在一个 Java 程序中,它有一个变量 t 来计算时间(相对于程序开始,而不是系统时间),我怎样才能将用户输入的字符串转换成一个数学公式在需要时进行有效评估。
(基本上,公式的准备可能会很慢,因为它发生在 运行 时间之前,但每个存储的函数可能在 运行 时间期间被调用多次,然后必须有效地评估)
因为我找不到一个数学解析器来保持加载公式供以后参考,而不是找到一个通用的图形来求解 y=f(x) 的方程,我正在考虑取而代之的是我的 Java 程序从输入字符串中生成脚本(JS、Python 等),然后使用当前 t 作为输入参数调用所述脚本。
-但是有人告诉我,脚本相当慢,因此对于实时应用程序来说不切实际。
有没有更有效的方法? (如果可行的话,我什至会考虑让我的 Java 应用程序为每个用户输入生成和编译 C 代码)
编辑:树结构确实可以存储表达式,但求值速度仍然相当慢,据我所知,我需要在求值时再次将其转换为表达式链(例如,遍历树对象) 比直接求解方程需要更多的调用。相反,我将尝试生成额外的 java 类.
我所做的是在运行时生成 Java 代码并编译它。有很多库可以帮助你做到这一点,我写的一个是 https://github.com/OpenHFT/Java-Runtime-Compiler 这样它可以像你自己手写 Java 代码一样高效,如果调用足够多的次数将被编译到本机代码。
您能否提供一些有关假设的函数类型和要求的性能的信息?也许只使用数学解析器库就足够了,它只预编译一次包含带有变量的数学公式的字符串,然后使用这种预编译形式的公式来传递结果,即使变量值正在变化?这种解决方案非常快,因为它通常不需要重复的字符串解析、语法检查等。
我最近在项目中使用的此类开源数学解析器的一个示例是 mXparser:
包含函数定义的用法示例
Function f = new Function("f(x,y) = sin(x) + cos(y)");
double v1 = f.calculate(1,2);
double v2 = f.calculate(3,4);
double v3 = f.calculate(5,6);
在上面的代码中,真正的字符串解析只会在计算 v1 之前完成一次。进一步计算 v1、v2(一个可能的 vn)将在快速模式下完成。
此外,您可以在字符串表达式中使用函数定义
Expression e = new Expression("f(1,2)+f(3,4)", f);
double v = e.calculate();
在一个 Java 程序中,它有一个变量 t 来计算时间(相对于程序开始,而不是系统时间),我怎样才能将用户输入的字符串转换成一个数学公式在需要时进行有效评估。 (基本上,公式的准备可能会很慢,因为它发生在 运行 时间之前,但每个存储的函数可能在 运行 时间期间被调用多次,然后必须有效地评估)
因为我找不到一个数学解析器来保持加载公式供以后参考,而不是找到一个通用的图形来求解 y=f(x) 的方程,我正在考虑取而代之的是我的 Java 程序从输入字符串中生成脚本(JS、Python 等),然后使用当前 t 作为输入参数调用所述脚本。 -但是有人告诉我,脚本相当慢,因此对于实时应用程序来说不切实际。
有没有更有效的方法? (如果可行的话,我什至会考虑让我的 Java 应用程序为每个用户输入生成和编译 C 代码)
编辑:树结构确实可以存储表达式,但求值速度仍然相当慢,据我所知,我需要在求值时再次将其转换为表达式链(例如,遍历树对象) 比直接求解方程需要更多的调用。相反,我将尝试生成额外的 java 类.
我所做的是在运行时生成 Java 代码并编译它。有很多库可以帮助你做到这一点,我写的一个是 https://github.com/OpenHFT/Java-Runtime-Compiler 这样它可以像你自己手写 Java 代码一样高效,如果调用足够多的次数将被编译到本机代码。
您能否提供一些有关假设的函数类型和要求的性能的信息?也许只使用数学解析器库就足够了,它只预编译一次包含带有变量的数学公式的字符串,然后使用这种预编译形式的公式来传递结果,即使变量值正在变化?这种解决方案非常快,因为它通常不需要重复的字符串解析、语法检查等。
我最近在项目中使用的此类开源数学解析器的一个示例是 mXparser:
包含函数定义的用法示例
Function f = new Function("f(x,y) = sin(x) + cos(y)");
double v1 = f.calculate(1,2);
double v2 = f.calculate(3,4);
double v3 = f.calculate(5,6);
在上面的代码中,真正的字符串解析只会在计算 v1 之前完成一次。进一步计算 v1、v2(一个可能的 vn)将在快速模式下完成。
此外,您可以在字符串表达式中使用函数定义
Expression e = new Expression("f(1,2)+f(3,4)", f);
double v = e.calculate();