Передача функции в качестве параметра - PullRequest
0 голосов
/ 06 марта 2011

Есть ли способ передать функцию в качестве параметра при запуске программы на C? Я реализую приложение для интегральной аппроксимации, и все, что мне нужно, это ввести функцию, с которой я хочу работать при запуске приложения. Я пытался (например) 2/(2+2*x), но я получаю только "2". Когда я пишу в приложение напрямую, нет проблем. Есть ли простой способ получить это? Может быть, перераспределить его на несколько параметров? Нравится

app.c number number*x number *x*x number *x*x*x... ?

Спасибо

Ответы [ 3 ]

2 голосов
/ 06 марта 2011

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

Например, 2 * x будет записано как:

app 2 x mul

Например, исходное выражение может бытьзаписано как:

app 2 2 2 x mul add div

Я оставляю реализацию в качестве упражнения, для этого вам не нужно больше страницы кода.

1 голос
/ 06 марта 2011

Это не ответ.Просто чтобы показать, что это не так сложно:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

typedef struct expr_s {
    char op;
    struct expr_s *exprA, *exprB;
    float value;
} expr;

int readExpr(expr *node, int argc, char *argv[]) {
    int argn = 1;
    assert(argc > 0);
    switch(argv[0][0]) {
    case '0' ... '9':
    case '-': case '.':
        node->op = '#'; // direct value
        node->value = atof(argv[0]);
        return 1;
    case 'x':
        if (argv[0][1] == '\0') { // variable
            node->op = 'x';
            return 1;
        }
        break;
    default: ;
    }
    // binary expr
    if (strcmp(argv[0], "mul") == 0) node->op = '*';
    else if (strcmp(argv[0], "add") == 0) node->op = '+';
    else if (strcmp(argv[0], "div") == 0) node->op = '/';
    else if (strcmp(argv[0], "sub") == 0) node->op = '-';
    else abort();
    node->exprA = (expr*)malloc(sizeof(expr));
    node->exprB = (expr*)malloc(sizeof(expr));
    argn += readExpr(node->exprA, argc-argn, argv+argn);
    argn += readExpr(node->exprB, argc-argn, argv+argn);
    return argn;
}

float evalExpr(expr *node, float x) {
    switch(node->op) {
    case '#': return node->value;
    case 'x': return x;
    case '*': return (evalExpr(node->exprA, x) * evalExpr(node->exprB, x));
    case '+': return (evalExpr(node->exprA, x) + evalExpr(node->exprB, x));
    case '/': return (evalExpr(node->exprA, x) / evalExpr(node->exprB, x));
    case '-': return (evalExpr(node->exprA, x) - evalExpr(node->exprB, x));
    default: abort();
    }
}

int main(int argc, char *argv[]) {
    expr rootExpr;
    float x;
    readExpr(&rootExpr, argc-1, argv+1);
    for(x=0; x < 5; x+=0.5) {
        printf("f(%f) = %f\n", x, evalExpr(&rootExpr, x));
    }
    return 0;
}

Rusult:

./playground div 2 add 2 mul 2 x
f(0.000000) = 1.000000
f(0.500000) = 0.666667
f(1.000000) = 0.500000
f(1.500000) = 0.400000
f(2.000000) = 0.333333
f(2.500000) = 0.285714
f(3.000000) = 0.250000
f(3.500000) = 0.222222
f(4.000000) = 0.200000
f(4.500000) = 0.181818

Обратите внимание, что если вы будете использовать обратную польскую запись, вы увидите почти то же самое,но со стеком expr вместо, если последующий вызов readExpr.

0 голосов
/ 06 марта 2011

Простой способ сделать это - сохранить выражение в файле, присвоить программе имя этого файла в качестве аргумента, а затем использовать system() или его эквивалент, чтобы оболочка интерпретировала и оценила выражение во время выполнения , Однако это будет довольно медленно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...