如何在c ++中使代数方程简化?

时间:2017-11-12 01:33:58

标签: c++

我实际上已经开始学习c ++了,如果有人能帮助我完成我的第一步,我将非常感激。 我必须在c ++中制作代数方程式简化器。例如这个等式: X + 5 + 6 + 3Y + 3 + 2Y 应该看起来像这样: X + 5Y + 14 没有划分,但程序应该使用+, - 和*。 我知道这对你们大多数人来说都很容易,但我会陷入困境,如果有人能告诉我应该如何开始,我会很高兴:/

提前谢谢你, 答案:)

2 个答案:

答案 0 :(得分:5)

首先,准确定义您需要使用的数学类型。这些是多项式,而不是代数方程。更容易简化。

接下来,选择一个数据结构来表示多项式。多项式是一个项的和,每个项都有一个系数,一组变量带有指数。在这种情况下,所有系数和指数都是整数。并且,让我们假设这些整数将落在正负十亿之内。

我们已经可以定义一些类了。

#include <vector>
#include <cstdint>

typedef std::int32_t value;

struct power {
    char variable;
    value degree;
};

struct monomial {
    value coefficient;
    std::vector< power > product;
};

struct polynomial {
    std::vector< monomial > sum;
};

接下来,在给定文本格式的类上定义输入和输出。

#include <iostream>

std::istream & operator >> ( std::istream & is, power & obj ) {
    // Skip leading space.
    std::istream::sentry s( is );

    // Read one character for the variable name.
    // Require that it be a letter.
    if ( is && std::isalpha( is.peek() ) ) {
        is >> obj.variable;
    } else {
        // Otherwise, the input is invalid.
        is.clear( std::ios::failbit );
    }

    // Read the exponent if its presence is indicated by a ^.
    if ( is ) {
        if ( is.peek() == '^' ) {
            is.ignore();
            is >> obj.degree;
        } else {
            obj.degree = 1;
            is.clear();
        }
    }
    return is;
}

std::ostream & operator << ( std::ostream & os, power const & obj ) {
    os << obj.variable;
    if ( obj.degree != 1 ) {
        os << '^' << obj.degree;
    }
    return os;
}

std::istream & operator >> ( std::istream & is, monomial & obj ) {
    obj.coefficient = 1;
    obj.product.clear();

    // Read a sequence of numbers and exponentiated variables,
    // optionally separated by * .
    bool did_read_asterisk = false;

    do {
        // Try reading a coefficient. (And ignore leading space.)
        value coefficient;
        if ( is >> coefficient ) {
            obj.coefficient *= coefficient;
        } else if ( is.rdstate() & std::ios::failbit ) {
            // If it was absent, tell iostream to resume input.
            is.clear( is.rdstate() & ~ std::ios::failbit );

            // Read a power instead.
            power p;
            if ( is >> p ) {
                obj.product.push_back( p );
            }

            // It's OK if the power was missing too, unless there was a * .
            if ( ! did_read_asterisk && ( is.rdstate() & std::ios::failbit ) ) {
                is.clear( is.rdstate() & ~ std::ios::failbit );
                return is;
            }
        }
        did_read_asterisk = false;

        // Skip trailing space.
        if ( is >> std::ws ) {
            if ( is.eof() ) {
                // Succeed if this is the end of input.
                return is;
            }
            if ( is.peek() == '*' ) {
                is.ignore();
                did_read_asterisk = true;
            }
            if ( is.peek() == '+' || is.peek() == '-' ) {
                break;
            }
        }
    } while ( is );

    return is;
}

std::ostream & operator << ( std::ostream & os, monomial const & obj ) {
    if ( obj.coefficient != 1 || obj.product.empty() ) {
        os << obj.coefficient;
    }
    for ( power const & p : obj.product ) {
        os << p;
    }
    return os;
}

std::istream & operator >> ( std::istream & is, polynomial & obj ) {
    // Skip leading space and reject EOF.
    std::istream::sentry s( is );

    // If there is no minus sign, start positive.
    bool positive = true;
    if ( is && is.peek() == '-' ) {
        is.ignore();
        positive = false;
    }

    // Read a sequence of monomials separated by + or - signs.
    monomial m;
    while ( is >> m ) {
        if ( ! positive ) m.coefficient = - m.coefficient;
        obj.sum.push_back( m );

        is >> std::ws;
        char next_op = is.peek();
        if ( is && ( next_op == '+' || next_op == '-' ) ) {
            is.ignore();
            positive = next_op == '+';

        } else if ( ! is.bad() ) {
            // Succeed if the next operator is missing.
            is.clear();
            return is;
        }
    }
    return is;
}

std::ostream & operator << ( std::ostream & os, polynomial const & obj ) {
    bool skip_leading_plus = true;

    for ( monomial const & m : obj.sum ) {
        if ( m.coefficient > 0 && ! skip_leading_plus ) {
            os << '+';
        }
        os << m;
        skip_leading_plus = false;
    }
    return os;
}

接下来,编写简化逻辑。

#include <algorithm>

struct variable_order {
    bool operator() ( power lhs, power rhs ) {
        return lhs.variable < rhs.variable;
    }
};
struct variable_same {
    bool operator() ( power lhs, power rhs ) {
        return lhs.variable == rhs.variable;
    }
};

monomial simplify( monomial in ) {
    std::sort( in.product.begin(), in.product.end(), variable_order{} );
    for ( auto it = in.product.begin();
        ( it = std::adjacent_find( it, in.product.end(), variable_same{} ) )
             != in.product.end(); ) {
        value degree = it->degree;
        it = in.product.erase( it );
        it->degree += degree;
    }
    in.product.erase( std::remove_if( in.product.begin(), in.product.end(),
        []( power p ) { return p.degree == 0; } ), in.product.end() );
    return in;
}

struct power_order {
    bool operator() ( power lhs, power rhs ) {
        return lhs.variable < rhs.variable? true
             : lhs.variable > rhs.variable? false
             : lhs.degree < rhs.degree;
    }
};
struct power_same {
    bool operator() ( power lhs, power rhs ) {
        return lhs.variable == rhs.variable
            && lhs.degree == rhs.degree;
    }
};

struct product_order {
    bool operator() ( monomial lhs, monomial rhs ) {
        return std::lexicographical_compare( lhs.product.begin(), lhs.product.end(),
                                             rhs.product.begin(), rhs.product.end(),
                                             power_order{} );
    }
};
struct product_same {
    bool operator() ( monomial lhs, monomial rhs ) {
        return std::equal( lhs.product.begin(), lhs.product.end(),
                           rhs.product.begin(), rhs.product.end(),
                           power_same{} );
    }
};

polynomial simplify( polynomial in ) {
    for ( auto & m : in.sum ) {
        m = simplify( m );
    }
    std::sort( in.sum.begin(), in.sum.end(), product_order{} );
    for ( auto it = in.sum.begin();
        ( it = std::adjacent_find( it, in.sum.end(), product_same{} ) )
             != in.sum.end(); ) {
        value coefficient = it->coefficient;
        it = in.sum.erase( it );
        it->coefficient += coefficient;
    }
    in.sum.erase( std::remove_if( in.sum.begin(), in.sum.end(),
        []( monomial m ) { return m.coefficient == 0; } ), in.sum.end() );

    // Represent zero rather than "nothing."
    if ( in.sum.empty() ) in = polynomial{{ monomial{ 0, {} } }};

    return in;
}

最后,将它们捆绑在一起。

int main() {
    polynomial p;
    std::cin >> p;
    std::cout << simplify( p ) << '\n';
}

看,C ++非常糟糕!

答案 1 :(得分:0)

这实际上是一个非常困难的问题。假设您将数据作为字符串使用,您需要在运算符上拆分字符串以获取2x14y等单个组件。然后,您需要使用某种正则表达式检查表达式中存在哪些变量,并将值转换为您将处于的任何向量空间中的向量。例如,如果您确定将使用的最大变量数为2,向量空间将在R3中。例如,5x将变为[0,5,0],其中第一个元素表示没有变量后缀的数字,第二个元素表示x的数量,第三个元素表示y的数量。最后你应该有大量的向量,你可以将它们相加到一个向量并将其转换回字符串以输出到屏幕。像sympy这样的Python库要求你输入你将要使用的变量,以便它在内部知道它将要计算的向量空间。

我们以您的问题为例。它将接受字符串x+5+6+3y+3+2y并在加号上拆分并删除额外的空格,给出单独的字符串x56等。然后你会将字符串转换为向量,在这种情况下,它们将是[0,1,0][5,0,0][6,0,0][0,0,3] ...其中第一个元素表示没有变量的数字的数量后缀,第二个元素,如果是x的数量等,那么你将总结所有向量以获得[14,1,5]的最终向量,然后你将它转换回字符串’14+1x+5y’,并将其打印到屏幕上。

这是线性代数中的一个概念,称为同构,您可以将一组向量转换为另一个向量空间,因此问题在计算上更容易(或可能)。在你的情况下,你将把P2(二次多项式)中的一组向量转换为R3(实数组中的三度向量),简化表达式,并将R3向量转换回P2以回馈给用户。因为我确定你已经搞清楚了,这个问题可能会更多一点,你已经准备好依赖数学,但这对你来说可能是一个很好的练习。无论如何。

希望这有帮助!