Шаблоны c ++ для представления полиномов - PullRequest
0 голосов
/ 22 февраля 2020

Я пытаюсь использовать шаблоны для представления простых многочленов, таких как x ^ 2 + 3x + 5. Моя идея состоит в том, чтобы представить их как сумму слагаемых, причем каждый член имеет коэффициент и степень, например, x ^ 2 имеет coeff = 1 и мощность = 2. Я также хочу иметь возможность оценить полиномы для некоторых х (у них есть только 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 () работать?

Ответы [ 3 ]

2 голосов
/ 22 февраля 2020

Да, вы можете сделать это, вам просто нужно вызвать 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;
}

или если вы наберете eval static, то вы можете позвонить Tail::eval(x) напрямую.

1 голос
/ 22 февраля 2020

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

Надеюсь, это поможет вам.

#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;
}

Запустите онлайн

1 голос
/ 22 февраля 2020

Полиномиальные коэффициенты могут быть сохранены в std::array или std::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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...