C ++のテンプレートを使用した導関数の計算

投稿に触発された。 途中で、私は独自のラムダ式の実装に似たものを得ました:)コンパイル段階でも導関数を計算する機能を備えています。 関数を指定するには、演算子+、-、*、/、およびいくつかの標準的な数学関数を使用できます。

Sqr-二乗

Sqrt-平方根

捕虜-べき乗

Exp-指数関数

ログ-対数

罪、Cos、Tg、Ctg、アシン、Acos、ATG、AcTG-三角法



導関数は、導関数を使用して計算されます。 入力にはファンクターがあり、出力には彼女もいます。 導関数を正確に計算するには、特別な構文を使用して定義されたファンクターを入力する必要があります。 構文は直感的です(少なくともそうすることを望みます)。 適切なシグネチャ(double-> double)を持つ他のファンクターまたはラムダが微分入力に適用される場合、微分は近似的に計算されます。

例:

#include <iostream> #include "CrazyMath.h" using namespace std; using namespace CrazyMath; auto global = Tg(X) + Ctg(X) + Asin(X) * Acos(X) - Atg(X) / Actg(X); auto d_global = derivative(global); int main() { auto f1 = (Pow(X, 3) + 2 * Sqr(X) - 4 * X + 1 / Sqrt(1 - Sqr(X))) * (Sin(X) + Cos(X) * (Log(5, X) - Exp(2, X))); auto f2 = derivative(f1) * Sqrt(X - Tg(X / 4)); auto f3 = [](double x) -> double { return sin(x); }; auto df1 = derivative(f1); auto df2 = derivative(f2); auto df3 = derivative(f3); cout << "f(x)\t\tf'(x)" << endl; cout << f1(0.5) << " \t" << df1(0.5) << endl; cout << f2(0.5) << " \t" << df2(0.5) << endl; cout << f3(0) << " \t" << df3(0) << endl; cout << global(0.5) << " \t" << d_global(0.5) << endl; char temp[4]; cout << "\nPress ENTER to exit..." << endl; cin.getline(temp, 3); return 0; }
      
      





次のように機能します。

 // CrazyMath.h,  //--------------------------------------------------- // base functions class Const { public: typedef Const Type; Const(double x) : m_const(x) {} double operator()(double) {} private: double m_const; }; class Simple { public: typedef Simple Type; double operator()(double x) { return x; } }; template <class F1, class F2> class Add { public: typedef typename Add<F1, F2> Type; Add(const F1& f1, const F2& f2) : m_f1(f1), m_f2(f2) {} double operator()(double x) { return m_f1(x) + m_f2(x); } F1 m_f1; F2 m_f2; }; //--------------------------------------------------- // helpers template <class F1, class F2> Add<F1, F2> operator+(const F1& f1, const F2& f2) { return Add<F1, F2>(f1, f2); } template <class F> Add<F, Const> operator+(double value, const F& f) { return Add<F, Const>(f, Const(value)); } template <class F> Add<F, Const> operator+(const F& f, double value) { return Add<F, Const>(f, Const(value)); } // other helpers ... //--------------------------------------------------- // derivatives template <class F> class Derivative { public: Derivative(const F& f, double dx = 1e-3) : m_f(f), m_dx(dx) {} double operator()(double x) { return (m_f(x + m_dx) - m_f(x)) / m_dx; } F m_f; double m_dx; typedef std::function<double (double)> Type; Type expression() { return [this](double x) -> double { return (m_f(x + m_dx) - m_f(x)) / m_dx; }; } }; template<> class Derivative<Const> { public: typedef Const Type; Derivative<Const> (Const) {} double operator()(double) { return 0; } Type expression() { return Const(0); } }; template<> class Derivative<Simple> { public: typedef Const Type; Derivative<Simple> (Simple) {} double operator()(double) { return 1; } Type expression() { return Const(1); } }; template <class F1, class F2> class Derivative< Add<F1, F2> > { public: Derivative< Add<F1, F2> > (const Add<F1, F2>& f) : m_df1(f.m_f1), m_df2(f.m_f2) { } double operator()(double x) { return m_df1(x) + m_df2(x); } Derivative<F1> m_df1; Derivative<F2> m_df2; typedef typename Add<typename Derivative<F1>::Type, typename Derivative<F2>::Type> Type; Type expression() { return m_df1.expression() + m_df2.expression(); } }; // other derivatives ... template <class F> typename Derivative<F>::Type derivative(F f) { return Derivative<F>(f).expression(); } extern Simple X;
      
      







CrazyMath.hファイルは非常に大きいことが判明したため、記事に完全に含めることは意味がありません。 興味がある人はGithubからソースをダウンロードできます



UPD Derivativeクラスに式メソッドを追加し、式メソッドが返す型に対応するtypedefを追加しました。 expressionメソッドは、さらに区別するのに適したファンクターを返します。 ただし、2次、3次、および高次の導関数を計算すると、式のサイズが急速に大きくなるため、コンパイルに時間がかかる場合があります。



All Articles