2010-04-04 3 views
4

Сегодня я работал над моей современной домашней работой по исчислению, и мы делаем некоторые методы итераций по методу Ньютона, чтобы найти решения для таких вещей, как x^2 = 2. Это заставило меня думать, что я могу написать функцию, которая будет принимать два указателя на функции: одну для самой функции и одну для производной и автоматизировать процесс. Это не было бы слишком сложным, тогда я начал думать, могу ли я ввести функцию пользователя и проанализировать этот ввод (да, я могу это сделать). Но могу ли я затем динамически создать указатель на функцию с одной переменной в C++. Например, если x^2 + x, я могу сделать функцию double function (double x) {return x * x + x;} во время выполнения. Является ли это дистанционно возможным, или это похоже на самонастраивающийся код?Динамическое создание функции указателя в C++

Edit:

Так что я полагаю, как это может быть сделано, если вы храните информацию в массиве и имел функцию, оцененную информацию, хранящуюся в массиве с заданным входом. Затем вы можете создать класс и инициализировать массив внутри этого класса, а затем использовать функцию оттуда. Есть ли способ лучше?

+0

Ruby, Python, Perl, JavaScript, Lisp или Scheme имеют функции для оценки строк, содержащих их собственный код, и очень естественно позволят вам делать то, что вы здесь задаете. –

+0

http://stackoverflow.com/questions/895077/dynamic-source-code-in-c http://stackoverflow.com/questions/1541429/how-to-run-c-code-from-c и вы можете Также вы можете быть заинтересованы в http://stackoverflow.com/questions/422594/derivatives-in-cc – dmckee

ответ

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()). Затем вы можете оценить это значение для заданного значения x с помощью e->eval(x).

Примечание: в приведенной выше коде, я игнорировал константную-корректность для ясности - не стоит :)

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'; 
} 
+0

Это работает только для полиномов ... что, если выражение 'x^x'? –

+0

@Peter: Это правда. – 2010-04-04 21:25:16

1

Вам не нужен собственный код модифицирования для этого. Но вы будете писать то, что сводится к парсеру и интерпретатору выражений. Вы пишете код для анализа вашей функции в подходящие структуры данных (например, деревья). Для данного ввода вы теперь проходите дерево и вычисляете результат функции. Расчет может быть выполнен через посетителя.

4

Как уже говорилось, вы не можете создавать новые функции C++ во время работы любым переносным способом. Однако вы можете создать выражение оценщика, который может оценить такие вещи, как:

(1 + 2) * 3 

, содержащейся в строке, во время выполнения. Нетрудно расширить такой оценщик, чтобы иметь переменные и функции.

1

Вам не нужно знать сборки. Напишите код C++ для возможных выражений, а затем напишите компилятор, который исследует выражение и выбирает соответствующие фрагменты кода. Это можно сделать во время выполнения, как это обычно делает интерпретатор, или это может быть этап компиляции, который создает код для выполнения путем копирования инструкций из каждой оценки выражения в выделенную память и затем устанавливает ее как функцию. Последнее сложнее понять и кодировать, но будет работать лучше.Но для времени разработки плюс время выполнения быть меньше, чем интерпретированная реализация, скомпилированный код должен использоваться много (миллиарды) раз.

0

Как и другие упомянули. Написание самомодифицирующегося кода вообще не требуется и является болезненным на скомпилированном языке, если вы хотите, чтобы он был переносимым. Самая сложная часть вашей работы - синтаксический анализ ввода. Я рекомендую muParser оценить ваши выражения. Это должно отнять много боли, и вы сможете сосредоточиться на важной части вашего проекта.

Смежные вопросы