我今天正在研究我的高级微积分作业,我们正在按照牛顿方法的方法做一些迭代方法来找到像x ^ 2 = 2这样的东西的解决方案。它让我想到我可以编写一个函数,它将带有两个函数指针,一个用于函数本身,另一个用于派生和自动化过程。这不会太具有挑战性,然后我开始思考我可以让用户输入一个函数并解析该输入(是的,我可以这样做)。但是我可以在c ++中动态创建指向单变量函数的指针。例如,如果x ^ 2 + x,我可以在运行时创建一个函数double函数(double x){return x * x + x;}。这是远程可行的,还是与自修改代码一致?
编辑:
所以我想如果你将信息存储在一个数组中并且有一个函数用给定的输入来评估存储在这个数组中的信息,我想这是怎么做的。然后你可以创建一个类并初始化该类内部的数组,然后从那里使用该函数。还有更好的方法吗?
答案 0 :(得分:4)
正如其他人所说,你不能以任何可移植的方式在运行时创建新的C ++函数。但是,您可以创建一个表达式计算器,可以评估以下内容:
(1 + 2) * 3
在运行时包含在字符串中。扩展这样的评估者以获得变量和功能并不困难。
答案 1 :(得分:3)
它遵循自修改代码的方式,并且有可能 - 而不是“纯粹的”C ++。您需要了解一些程序集和一些实现细节。在不走这条路的情况下,您可以抽象地表示操作(例如使用仿函数)并构建要评估的表达式树。
但是,对于您给出的一个变量的简单情况,您只需要存储系数,并且可以轻松地评估给定值的那些。
// store coefficients as vector in "reverse" order, e.g. 1x^2 - 2x + 3
// is stored as [3, -2, 1]
typedef double Num;
typedef vector<double> Coeffs;
Num eval(Coeffs c, Num x) {
assert(c.size()); // must not be empty
Num result = 0;
Num factor = 1;
for (Coeffs::const_iterator i = c.begin(); i != c.end(); ++i) {
result += *i * factor;
factor *= x;
}
return result;
}
int main() {
Coeffs c; // x^2 + x + 0
c.push_back(0);
c.push_back(1);
c.push_back(1);
cout << eval(c, 0) << '\n';
cout << eval(c, 1) << '\n';
cout << eval(c, 2) << '\n';
}
答案 2 :(得分:3)
您无法动态创建函数,因为您可以为其生成原始机器代码,但您可以使用多态轻松创建数学表达式:
struct Expr
{
virtual double eval(double x) = 0;
};
struct Sum : Expr
{
Sum(Expr* a, Expr* b):a(a), b(b) {}
virtual double eval(double x) {return a->eval(x) + b->eval(x);}
private:
Expr *a, *b;
};
struct Product : Expr
{
Product(Expr* a, Expr* b):a(a), b(b) {}
virtual double eval(double x) {return a->eval(x) * b->eval(x);}
private:
Expr *a, *b;
};
struct VarX : Expr
{
virtual double eval(double x) {return x;}
};
struct Constant : Expr
{
Constant(double c):c(c) {}
virtual double eval(double x) {return c;}
private:
double c;
};
然后,您可以在运行时将表达式解析为Expr
对象。例如,x^2+x
将是Expr* e = new Sum(new Product(new VarX(), new VarX()), new VarX())
。然后,您可以使用e->eval(x)
为给定的 x 值评估该值。
注意:在上面的代码中,为了清楚起见,我忽略了const-correctness - 你不应该:)
答案 3 :(得分:1)
你真的不需要自我修改代码。但是你将编写归结为表达式解析器和解释器的内容。您编写代码以将您的函数解析为合适的数据结构(例如树)。对于给定的输入,您现在遍历树并计算函数的结果。可以通过访客进行计算。
答案 4 :(得分:1)
您不需要知道装配。编写可能的表达式的c ++代码,然后编写一个编译器来检查表达式并选择适当的代码片段。这可以在运行时完成,就像解释器通常那样,或者它可以是一个编译阶段,它通过将指令从每个表达式求值复制到已分配的内存中然后将其设置为函数来创建要执行的代码。后者更难理解和编码,但会表现更好。但是对于开发时间加上执行时间小于解释实现,编译后的代码必须使用很多次(数十亿次)。
答案 5 :(得分:0)
正如其他人所说。编写自修改代码根本不是必需的,如果您希望它是可移植的,那么在编译语言中是很痛苦的。 你工作中最难的部分是解析输入。我建议muParser评估您的表达式。它应该消除很多痛苦,你将能够专注于项目的重要部分。