Оценка математических выражений

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

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

12
задан abelenky 21 July 2009 в 02:01
поделиться

4 ответа

Альтернативой реализации вашего собственного синтаксического анализатора и оценщика выражений было бы связывание с библиотекой, которая предоставляет один для вас. Интересным выбором был бы легко встраиваемый язык сценариев, такой как Lua .

Просто настроить экземпляр интерпретатора Lua и передать ему выражения для оценки, возвращая функцию для вызова, которая оценивает выражение. Вы даже можете позволить пользователю иметь переменные ...

Обновление: LE, простой оценщик выражений с использованием Lua

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

Я скомпилировал и протестировал это в Windows, используя Lua 5.1.4 из Lua для Windows . На других платформах вам нужно будет найти Lua из обычного источника или с www.lua.org.

Открытый интерфейс для LE

Вот файл le.h :

/* Public API for the LE library.
 */
int le_init();
int le_loadexpr(char *expr, char **pmsg);
double le_eval(int cookie, char **pmsg);
void le_unref(int cookie);
void le_setvar(char *name, double value);
double le_getvar(char *name);

Пример кода с использованием LE

Вот файл t-le.c, демонстрирующий простое использование этой библиотеки. Он берет свой единственный аргумент командной строки, загружает его как выражение и оценивает его с изменением глобальной переменной x от 0,0 до 1,0 за 11 шагов:

#include <stdio.h>
#include "le.h"

int main(int argc, char **argv)
{
    int cookie;
    int i;
    char *msg = NULL;

    if (!le_init()) {
    printf("can't init LE\n");
    return 1;
    }
    if (argc<2) {
    printf("Usage: t-le \"expression\"\n");
    return 1;
    }
    cookie = le_loadexpr(argv[1], &msg);
    if (msg) {
    printf("can't load: %s\n", msg);
    free(msg);
    return 1;
    }
    printf("  x    %s\n"
       "------ --------\n", argv[1]);
    for (i=0; i<11; ++i) {
    double x = i/10.;
    double y;

    le_setvar("x",x);
    y = le_eval(cookie, &msg);
    if (msg) {
        printf("can't eval: %s\n", msg);
        free(msg);
        return 1;
    }
    printf("%6.2f %.3f\n", x,y);
    }
}

Вот некоторые выходные данные t-le:

E:...>t-le "math.sin(math.pi * x)"
  x    math.sin(math.pi * x)
------ --------
  0.00 0.000
  0.10 0.309
  0.20 0.588
  0.30 0.809
  0.40 0.951
  0.50 1.000
  0.60 0.951
  0.70 0.809
  0.80 0.588
  0.90 0.309
  1.00 0.000

E:...>

Реализация LE

Вот le.c , реализующий оценщик Lua Expression:

#include <lua.h>
#include <lauxlib.h>

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

static lua_State *L = NULL;

/* Initialize the LE library by creating a Lua state.
 *
 * The new Lua interpreter state has the "usual" standard libraries
 * open.
 */
int le_init()
{
    L = luaL_newstate();
    if (L) 
    luaL_openlibs(L);
    return !!L;
}

/* Load an expression, returning a cookie that can be used later to
 * select this expression for evaluation by le_eval(). Note that
 * le_unref() must eventually be called to free the expression.
 *
 * The cookie is a lua_ref() reference to a function that evaluates the
 * expression when called. Any variables in the expression are assumed
 * to refer to the global environment, which is _G in the interpreter.
 * A refinement might be to isolate the function envioronment from the
 * globals.
 *
 * The implementation rewrites the expr as "return "..expr so that the
 * anonymous function actually produced by lua_load() looks like:
 *
 *     function() return expr end
 *
 *
 * If there is an error and the pmsg parameter is non-NULL, the char *
 * it points to is filled with an error message. The message is
 * allocated by strdup() so the caller is responsible for freeing the
 * storage.
 * 
 * Returns a valid cookie or the constant LUA_NOREF (-2).
 */
int le_loadexpr(char *expr, char **pmsg)
{
    int err;
    char *buf;

    if (!L) {
    if (pmsg)
        *pmsg = strdup("LE library not initialized");
    return LUA_NOREF;
    }
    buf = malloc(strlen(expr)+8);
    if (!buf) {
    if (pmsg)
        *pmsg = strdup("Insufficient memory");
    return LUA_NOREF;
    }
    strcpy(buf, "return ");
    strcat(buf, expr);
    err = luaL_loadstring(L,buf);
    free(buf);
    if (err) {
    if (pmsg)
        *pmsg = strdup(lua_tostring(L,-1));
    lua_pop(L,1);
    return LUA_NOREF;
    }
    if (pmsg)
    *pmsg = NULL;
    return luaL_ref(L, LUA_REGISTRYINDEX);
}

/* Evaluate the loaded expression.
 * 
 * If there is an error and the pmsg parameter is non-NULL, the char *
 * it points to is filled with an error message. The message is
 * allocated by strdup() so the caller is responsible for freeing the
 * storage.
 * 
 * Returns the result or 0 on error.
 */
double le_eval(int cookie, char **pmsg)
{
    int err;
    double ret;

    if (!L) {
    if (pmsg)
        *pmsg = strdup("LE library not initialized");
    return 0;
    }
    lua_rawgeti(L, LUA_REGISTRYINDEX, cookie);
    err = lua_pcall(L,0,1,0);
    if (err) {
    if (pmsg)
        *pmsg = strdup(lua_tostring(L,-1));
    lua_pop(L,1);
    return 0;
    }
    if (pmsg)
    *pmsg = NULL;
    ret = (double)lua_tonumber(L,-1);
    lua_pop(L,1);
    return ret;
}


/* Free the loaded expression.
 */
void le_unref(int cookie)
{
    if (!L)
    return;
    luaL_unref(L, LUA_REGISTRYINDEX, cookie);    
}

/* Set a variable for use in an expression.
 */
void le_setvar(char *name, double value)
{
    if (!L)
    return;
    lua_pushnumber(L,value);
    lua_setglobal(L,name);
}

/* Retrieve the current value of a variable.
 */
double le_getvar(char *name)
{
    double ret;

    if (!L)
    return 0;
    lua_getglobal(L,name);
    ret = (double)lua_tonumber(L,-1);
    lua_pop(L,1);
    return ret;
}

Замечания

Приведенный выше образец состоит из 189 строк всего кода, включая разбросанные комментарии, пустые строки и демонстрация.

6
ответ дан 2 December 2019 в 03:38
поделиться

Здесь вам нужен алгоритм Shunting Yard Algorithm .

Он позволяет преобразовать выражение in-fix в обратную польскую нотацию , который довольно просто оценить программно.

Алгоритм маневровой верфи довольно сложен, но мой опыт показывает, что вы можете закодировать его так, как он написан, и все это работает - вам не нужно беспокоиться о анализируя его.

14
ответ дан 2 December 2019 в 03:38
поделиться

Вы можете использовать Алгоритм маневрового двора , он отлично работает и позволяет вам легко разбирать функции и т. Д. На самом деле он не вычисляет его, но преобразует выражение в ONP, которое можно очень легко вычислить.

0
ответ дан 2 December 2019 в 03:38
поделиться

Я попросил у Google "синтаксический анализатор выражений рекурсивного спуска" (я не виню вас в том, что вы не знаете, что искать) и нашел Анализ выражений с помощью рекурсивного спуска , который обеспечивает введение в некоторые полезные методы синтаксического анализа.

Кроме того, статья в Википедии о парсере рекурсивного спуска включает довольно полный пример на C.

18
ответ дан 2 December 2019 в 03:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: