Итак, хотя я очень рад найти много ответов на Stack Overflow, я решил, что пришло время задать вопрос самому.
Я пытаюсь использовать алгоритм поиска корня с производными. В соответствии с GSL я должен заранее определить функцию и ее производную. Но мне интересно, можно ли сделать это более элегантно с помощью оболочки.
Некоторое время назад я нашел очень удобный шаблон (оболочка GSL C++) который отлично работает для одной функции, например интегрировать, и я активно использую его.
Теперь мне интересно, можно ли расширить этот подход, чтобы предоставить две функции для GSL, а именно саму функцию и ее производную.
Изменить: Решение
template <typename F, typename G>
class gsl_root_deriv : public gsl_function_fdf
{
private:
const F& _f;
const G& _df;
static double invoke_f(double x, void* params){
return static_cast<gsl_root_deriv*>(params) -> _f(x);
}
static double invoke_df(double x, void* params){
return static_cast<gsl_root_deriv*>(params) -> _df(x);
}
static void invoke_fdf(double x, void* params, double* f, double* df){
(*f) = static_cast<gsl_root_deriv*>(params) -> _f(x);
(*df) = static_cast<gsl_root_deriv*>(params) -> _df(x);
}
public:
gsl_root_deriv(const F& f_init, const G& df_init)
: _f(f_init), _df(df_init)
{
f = &gsl_root_deriv::invoke_f;
df = &gsl_root_deriv::invoke_df;
fdf = &gsl_root_deriv::invoke_fdf;
params = this;
}
};
И минимальный пример, напоминающий пример из GSL:
#include <iostream>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_roots.h>
#include <memory>
#include "gsl_root_deriv.h"
int main()
{
auto f = [](double x) -> double { return 0.25 * x*x - 1.0; };
auto df = [](double x) -> double { return 0.5 * x; };
gsl_root_deriv<decltype(f),decltype(df)> Fp(f,df);
int status(0), iter(0), max_iter(100);
const gsl_root_fdfsolver_type* T( gsl_root_fdfsolver_newton);
std::unique_ptr<gsl_root_fdfsolver,void(*)(gsl_root_fdfsolver*)>
s(gsl_root_fdfsolver_alloc(T),gsl_root_fdfsolver_free);
double x_0(0.0), x(5.0);
gsl_root_fdfsolver_set( s.get(), &Fp, x );
do
{
iter++;
std::cout << "Iteration " << iter << std::endl;
status = gsl_root_fdfsolver_iterate( s.get() );
x_0 = x;
x = gsl_root_fdfsolver_root( s.get() );
status = gsl_root_test_delta( x, x_0, 0.0, 1.0e-3 );
} while( status == GSL_CONTINUE && iter < max_iter );
std::cout << "Converged to root " << x << std::endl;
return 0;
}
С уважением,
-- Клаус