首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >构建计算机代数系统

构建计算机代数系统
EN

Stack Overflow用户
提问于 2011-03-24 06:45:31
回答 3查看 4.8K关注 0票数 13

我正在用PHP创建一个CAS (计算机代数系统),但是我现在卡住了。我正在使用this website

现在我写了一个记号赋予器。它将转换如下方程式:

代码语言:javascript
复制
1+2x-3*(4-5*(3x))

要这样做:

代码语言:javascript
复制
NUMBER PLUS_OPERATOR NUMBER VAR[X] MINUS_OPERATOR NUMBER MULTIPLY_OPERATOR GROUP

(其中group是另一组令牌)。我如何简化这个方程式呢?是的,我知道你可以做什么:添加X-var,但它们在子组中。我能用来处理这些令牌的最佳方法是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-24 11:52:21

真正有用的下一步是构建一个解析树:

您可以通过编写一个中缀解析器来创建其中的一个。您可以通过编写一个简单的递归下降解析器或引入大块头和using a parser generator来实现这一点。在这两种情况下,构建一个形式语法都是有帮助的:

代码语言:javascript
复制
expression: additive

additive: multiplicative ([+-] multiplicative)*

multiplicative: primary ('*' primary)*

primary: variable
       | number
       | '(' expression ')'

请注意,此语法不处理2x语法,但它应该很容易添加。

注意语法规则中对递归的巧妙使用。primary仅捕获变量、数字和带括号的表达式,并在遇到运算符时停止。multiplicative解析一个或多个由*符号分隔的primary表达式,但在遇到+-符号时停止。additive解析一个或多个由+-分隔的multiplicative表达式,但在遇到)时停止。因此,递归方案决定了运算符的优先顺序。

就像我在下面(see full example at ideone.com)所做的那样,手动实现predictive parser并不是很困难:

代码语言:javascript
复制
function parse()
{
    global $tokens;
    reset($tokens);
    $ret = parseExpression();
    if (current($tokens) !== FALSE)
        die("Stray token at end of expression\n");
    return $ret;
}

function popToken()
{
    global $tokens;
    $ret = current($tokens);
    if ($ret !== FALSE)
        next($tokens);
    return $ret;
}

function parseExpression()
{
    return parseAdditive();
}

function parseAdditive()
{
    global $tokens;

    $expr = parseMultiplicative();

    for (;;) {
        $next = current($tokens);
        if ($next !== FALSE && $next->type == "operator" &&
            ($next->op == "+" || $next->op == "-"))
        {
            next($tokens);
            $left = $expr;
            $right = parseMultiplicative();
            $expr = mkOperatorExpr($next->op, $left, $right);
        } else {
            return $expr;
        }
    }
}

function parseMultiplicative()
{
    global $tokens;

    $expr = parsePrimary();

    for (;;) {
        $next = current($tokens);
        if ($next !== FALSE && $next->type == "operator" &&
            $next->op == "*")
        {
            next($tokens);
            $left = $expr;
            $right = parsePrimary();
            $expr = mkOperatorExpr($next->op, $left, $right);
        } else {
            return $expr;
        }
    }
}

function parsePrimary()
{
    $tok = popToken();
    if ($tok === FALSE)
        die("Unexpected end of token list\n");
    if ($tok->type == "variable")
        return mkVariableExpr($tok->name);
    if ($tok->type == "number")
        return mkNumberExpr($tok->value);
    if ($tok->type == "operator" && $tok->op == "(") {
        $ret = parseExpression();
        $tok = popToken();
        if ($tok->type == "operator" && $tok->op == ")")
            return $ret;
        else
            die("Missing end parenthesis\n");
    }

    die("Unexpected $tok->type token\n");
}

好了,现在你有了这个可爱的解析树,甚至还有一张漂亮的图片。这次又是什么?您的目标(目前)可能是简单地组合术语以获得表单的结果:

代码语言:javascript
复制
n1*a + n2*b + n3*c + n4*d + ...

我会把那部分留给你。拥有一个解析树应该会让事情变得更加简单。

票数 21
EN

Stack Overflow用户

发布于 2011-03-24 06:59:20

PHP擅长字符串、数字和数组。但对于实现符号公式操作来说,它是一种糟糕的语言,因为它没有处理“符号表达式”的本机机制,而您确实需要树。是的,你可以实现所有这些机制。更难的是做代数运算。如果你想构建一些半复杂的东西,那会有相当多的工作量。理想情况下,您希望机器能够帮助您直接、轻松地编写转换。

例如,您将如何实现任意代数规则?结合性和交换性?术语“远距离匹配”,例如:

代码语言:javascript
复制
  (3*a+b)-2(a-b)+a ==> 3a-b

你可以看看a simple CAS can be implemented是如何使用我们的DMS program transformation system的。DMS具有内置的交换性和结合性等严格的数学结构,您可以显式编写代数规则来对符号公式进行操作。

票数 3
EN

Stack Overflow用户

发布于 2013-01-02 09:02:42

Computer Algebra and Symbolic Computation: Mathematical Methods by Joel S. Cohen一书描述了一种自动简化代数表达式的算法。

该算法在C#的Symbolism计算机代数库中使用。在您的示例中,使用以下C#程序:

代码语言:javascript
复制
var x = new Symbol("x");

(1 + 2 * x - 3 * (4 - 5 * (3 * x)))
    .AlgebraicExpand()
    .Disp();

在控制台上显示以下内容:

代码语言:javascript
复制
-11 + 47 * x
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5412612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档