【问题标题】:c++ templates to represent polynomialsc++模板来表示多项式
【发布时间】:2020-02-22 17:24:47
【问题描述】:

我正在尝试使用模板来表示简单的多项式,例如 x^2 + 3x + 5。我的想法是将它们表示为项的总和,每个项都有一个系数和一个幂,例如x^2 具有 coeff=1 和 power=2。我还希望能够评估某些 x 的多项式(它们只有 1 个未知数,但在很多地方)。到目前为止,我有:

struct PolyEnd{
    double eval(double x){
        return 0;
    }
};

template <int coeff, int power, class Tail> struct Poly {
    typedef Tail tt;

    double eval(double x){
        double curr = coeff * std::pow(x, power);
        return curr; // has to call eval(x) on rest of the terms which are in the tail and return the sum with "curr"
    }
};

int main()
{
    double x = 2;
    Poly<1,1,Poly<1,1,PolyEnd>> poly;
    std::cout << poly.eval(x) << std::endl;

    return 0;
}

但是,我被卡住了。我正在尝试的甚至可能吗?如果是这样,我怎样才能使递归 eval() 调用起作用?

【问题讨论】:

    标签: c++ templates template-meta-programming template-specialization


    【解决方案1】:

    是的,你可以这样做,你只需要在尾部调用eval,因为所有的类都是无状态的,你可以创建一个实例来当场调用成员函数:

    struct PolyEnd{
        double eval(double x){
            return 0;
        }
    };
    
    template <int coeff, int power, class Tail> struct Poly {
        typedef Tail tt;
    
        double eval(double x){
            double curr = coeff * std::pow(x, power);
            return curr + Tail{}.eval(x);
        }
    };
    
    int main()
    {
        double x = 2;
        Poly<1,1,Poly<1,1,PolyEnd>> poly;
        std::cout << poly.eval(x) << std::endl;
    
        return 0;
    }
    

    或者如果您拨打evalstatic,那么您可以直接拨打Tail::eval(x)

    【讨论】:

    • 谢谢!还有一件事——我怎么能代表 (x-2)^2?有什么想法吗?
    • @Parankush 我不知道你为什么要这样做。这样的事情通常只有在您打算在编译时对多项式进行转换时才有用,例如表达式模板。对多项式进行表示、解析和转换的意义取决于您和您的具体用例。
    • @Parankush:这不是多项式,所以你需要一些完全不同的东西并且方式更复杂。
    【解决方案2】:

    我猜你正在尝试元编程。你的问题也让我很兴奋,因为我也是元编程的新手,我想练习。 @walnut 的答案已被接受,但分享另一个实现没有害处。我使用了一些基本的元编程技术。

    希望对你有帮助。

    #include <cmath>
    #include <iostream>
    #include <string>
    
    template<int Value>
    struct coeff
    {   };
    
    template<int Value>
    struct power
    {   };
    
    template<typename Coefficient, typename Power>
    struct term;
    
    template<int Coefficient , int Power>
    struct term< coeff<Coefficient> , power<Power> >
    {
        inline double eval( double  x ) const noexcept { 
            return Coefficient * std::pow( x , Power );
        }
    };
    
    template<int Value>
    using constant = term< coeff<Value> , power<1> >;
    
    template<int Value>
    using exponential = term< coeff<1> , power<Value> >;
    
    template<typename... T>
    struct polynomial
    {
    
        static_assert( sizeof...(T) == 0, "A polynomial can only be expressed in 'term's.");
    
        [[nodiscard]] constexpr double eval( double ) const noexcept {
            return 0;
        }
    
        [[nodiscard]] std::string to_string() const noexcept {
            return std::string{};
        }
    };
    
    template<int Coefficient, int Power, typename... Tail>
    struct polynomial<term< coeff<Coefficient> , power<Power> >, Tail...>
           :   polynomial<Tail...>
    {
        [[nodiscard]] constexpr double eval( double x ) const noexcept {
            return m_t.eval( x ) + polynomial<Tail...>::eval( x );
        }
    
        [[nodiscard]] std::string to_string(){
            using namespace std;
            using namespace std::string_literals;
            return "("s + std::to_string( Coefficient ) + 
                   string { "x^" } +
                   std::to_string( Power ) + ( sizeof...(Tail) == 0 ? ")" : ") + " ) + 
                   polynomial<Tail...>::to_string();
        }
    
        private:
    
            term< coeff<Coefficient> , power<Power> > m_t;
    
    };
    
    int main()
    {
        auto p1 = polynomial<term< coeff<1> , power<2> > ,
                             term< coeff<2> , power<4> > ,
                             term< coeff<2> , power<3> > ,
                             constant<3> ,
                             exponential<2> >{};
    
        std::cout << "Polynomial is : " << p1.to_string() << std::endl;
        std::cout << "f(2) : " << p1.eval( 2 ) << std::endl;
        std::cout << "f(3) : " << p1.eval( 3 ) << std::endl;
        return 0;
    }
    

    run online

    【讨论】:

      【解决方案3】:

      多项式系数可以存储在std::arraystd::vector(如果您在运行时定义多项式次数)。

      然后用eval函数扩展功能。

      template <unsigned N>
      class Poly : public std::array<double, N> {
      public:
        template <typename... E>
        Poly(E &&... e) : std::array<double, N>{{std::forward<E>(e)...}} {}
      
        double eval(double x) {
          double result = 0;
          double exp = 1.;
          for (auto it = this->rbegin(); it != this->rend(); ++it) {
            result += exp * (*it);
            exp *= x;
          }
          return result;
        }
      };
      

      用法

      double result = Poly<3>{3., 2., 1.}.eval(17);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多