在 Qt 中计算数学表达式
Evaluate a math expression in Qt
我正在尝试创建一个Qt应用程序,我需要一个数学表达式计算器来评估这样的东西,例如(4 + 5(* 2-9/3。我将这个库(http://www.partow.net/programming/exprtk/(的.hpp文件包含在Qt Creator中的项目中,并尝试启动以下代码示例:
#include <cstdio>
#include <string>
#include "exprtk.hpp"
int main()
{
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
std::string expression_string = "3 + sqrt(5) + pow(3,2) + log(5)";
expression_t expression;
parser_t parser;
if (parser.compile(expression_string,expression))
{
double result = expression.value();
printf("Result: %19.15n",result);
}
else
printf("Error in expressionn.");
return 0;
}
当我尝试编译并运行它时,我得到以下输出:
debugmain.o:-1: error: too many sections (62303)
可能是什么问题?
仅使用纯Qt
您可以执行以下操作:
QString expression_string("3 + Math.sqrt(5) + Math.pow(3,2) + Math.log(5)");
QScriptEngine expression;
double my_val=expression.evaluate(expression_string).toNumber();
你可以做更多的事情,看看 这里 和 这里
,在我的机器上(Qt 5.5,带有g ++ 5.3的Ubuntu 16.04(,上面的代码不起作用。
尽管答案很老,但我把我的解决方案放在有人发现它有用的情况下。
QScriptEngine 使用 JavaScript 语法。因此,为了使上面的代码正常工作,我不得不将语法更改为:
QString expression_string("3 + Math.sqrt(5) + Math.pow(3,2) + Math.log(5)");
QScriptEngine expression;
double my_val=expression.evaluate(expression_string).toNumber();
按照注释中的请求,这里是如何使用boost::spirit
实现算术解析器。首先,你需要下载 boost 压缩包,不要试图从 GitHub 单独克隆 Spirit,因为它有来自其他提升库的依赖关系。
Boost 是巨大的,所以如果你只想要一个足够用于解析器的子集,你可以使用 bcp
提取它。从提升源目录:
cd tools/build/src/engine
./build.sh
cd ../../../bcp
../build/src/engine/b2
cd ../..
dist/bin/bcp fusion/include hana/functional spirit/home/x3 /some/path
bcp
将复制所有依赖项。你可以只保留/some/path/boost
目录,因为我们需要的所有库都只是标头。
最后,这里是解析器的完整代码。
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/hana/functional/fix.hpp>
#include <boost/hana/functional/overload.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
using namespace boost::spirit;
namespace hana = boost::hana;
// Define AST. The root is `ast::expr`, which is the first left-hand side
// operand and a list of all operations on the right-hand side. Each operand is
// a recursive `variant` that has `ast::expr` inside.
namespace ast
{
struct nil {};
struct signed_;
struct expr;
struct operand : x3::variant<
nil
, double
, x3::forward_ast<signed_>
, x3::forward_ast<expr>
>
{
using base_type::base_type;
using base_type::operator=;
};
struct signed_
{
char sign;
operand operand_;
};
struct operation
{
char operator_;
operand operand_;
};
struct expr
{
operand first;
std::vector<operation> rest;
};
} // namespace ast
// Give the grammar access to the fields of AST.
BOOST_FUSION_ADAPT_STRUCT(ast::signed_, sign, operand_)
BOOST_FUSION_ADAPT_STRUCT(ast::operation, operator_, operand_)
BOOST_FUSION_ADAPT_STRUCT(ast::expr, first, rest)
// Arithmetic expression grammar definition.
namespace ArithExpr
{
x3::rule<class expression, ast::expr > const expression("expression");
x3::rule<class term, ast::expr > const term("term");
x3::rule<class factor, ast::operand> const factor("factor");
auto const expression_def =
term
>> *(
(x3::char_('+') >> term)
| (x3::char_('-') >> term)
);
auto const term_def =
factor
>> *(
(x3::char_('*') >> factor)
| (x3::char_('/') >> factor)
);
auto const factor_def =
x3::double_
| '(' >> expression >> ')'
| (x3::char_('-') >> factor)
| (x3::char_('+') >> factor);
BOOST_SPIRIT_DEFINE(expression, term, factor);
auto calc = expression;
} // namespace ArithExpr
template <typename Iterator>
double CalcArithExpr(Iterator const &first, Iterator last) {
ast::expr expr;
// Build AST.
if (!x3::phrase_parse(first, last, ArithExpr::calc, x3::ascii::space, expr)) {
throw std::runtime_error("Cannot parse arithmetic expression");
}
// Parse the AST and calculate the result.
// hana::fix allows recursive lambda call
auto astEval = hana::fix([](auto self, auto expr) -> double {
// hana::overload calls a lambda corresponding to the type in the variant
return hana::overload(
[](ast::nil) -> double {
BOOST_ASSERT(0);
return 0;
},
[](double x) -> double { return x; },
[&](ast::signed_ const &x) -> double {
double rhs = boost::apply_visitor(self, x.operand_);
switch (x.sign) {
case '-': return -rhs;
case '+': return +rhs;
}
BOOST_ASSERT(0);
return 0;
},
[&](ast::expr const &x) -> double {
return std::accumulate(
x.rest.begin(), x.rest.end(),
// evaluate recursively left-hand side
boost::apply_visitor(self, x.first),
[&](double lhs, const ast::operation &op) -> double {
// evaluate recursively right-hand side
double rhs = boost::apply_visitor(self, op.operand_);
switch (op.operator_) {
case '+': return lhs + rhs;
case '-': return lhs - rhs;
case '*': return lhs * rhs;
case '/': return lhs / rhs;
}
BOOST_ASSERT(0);
return 0;
}
);
}
)(expr);
});
return astEval(expr);
}
int main(int argc, char *argv[]) {
auto expr = std::string{"-(4.5 + 5e-1) * 2.22 - 9.1 / 3.45"};
std::cout << CalcArithExpr(expr.begin(), expr.end()) << std::endl;
}
它计算-(4.5 + 5e-1) * 2.22 - 9.1 / 3.45
并输出-13.7377
。
更新
以下是如何在 Windows 上构建bcp
和复制所选标头的说明。虽然,没有任何保证。在 Linux 中一切正常,在 Windows 上它总是跳过一些箍,跳跃的方向总是不可预测的。
话虽如此,请打开PowerShell命令行。那里
Import-Module 'C:Program Files (x86)Microsoft Visual Studio2019ProfessionalCommon7ToolsMicrosoft.VisualStudio.DevShell.dll'
Install-Module VSSetup -Scope CurrentUser
Get-VSSetupInstance
将上面的 2019 替换为您的 VS 版本。对于PowerShell,您只需执行一次操作。剩下的就是每次你需要建造bcp
的时候。 上面的Get-VSSetupInstance
将打印有关计算机上的Visual Studio实例的信息。写下您想要使用的InstanceId
。现在切换到 PowerShell 中的 boost 目录,然后:
Enter-VsDevShell InstanceId -DevCmdArguments '-arch=x64' -SkipAutomaticLocation
其中InstanceId
是您从Get-VSSetupInstance
获得的 ID。然后从同一个命令提示符
cd toolsbuildsrcengine
& .build.bat
cd ......bcp
..buildsrcengineb2 address-model=64
cd ....
distbinbcp fusioninclude hanafunctional spirithomex3 X:somepathboost
- (C++)分析树以计算返回错误值的简单算术表达式
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 编译器是否强制根据模板参数计算表达式?
- 为什么'typeid(x) == typeid(y)'的计算结果为 true,其中 'x' 和 'y' 分别是 T 和 T& 类型的 id-表达式?
- 如何在常量计算表达式中获取编译时错误?
- 计算阶乘的 C++17 倍表达式中的错误
- 计算表达式字符串由 std::map 中的键组成
- 复合赋值的左侧表达式是未初始化的值.计算出的值也将是垃圾
- 使用正则表达式C++计算数字中的十进制空格
- 是否可以定义以后可以计算的布尔表达式
- 如何使用 ASCII 转换使用字符堆栈计算后缀表达式
- std::d eclval 和未计算的表达式
- (类型)(数学表达式)是否计算此类型的表达式?
- 使用不同的表达式计算同一整数时的结果不一致
- 手动将二进制表达式计算为十六进制
- 使用链表在C++进行表达式计算
- 表示表达式计算c++(多态性设计)
- 此表达式计算什么
- 将空表达式计算为NOP