📄 gsl_brent.c
字号:
#define RCSID "$Id: gsl_brent.c,v 1.7 2006/02/25 15:00:24 geuzaine Exp $"/* * Copyright (C) 1997-2006 P. Dular, C. Geuzaine * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * * Please report all bugs and problems to <getdp@geuz.org>. */#include "GetDP.h"#if defined(HAVE_GSL)#include "Numeric.h"#include <gsl/gsl_errno.h>#include <gsl/gsl_math.h>#include <gsl/gsl_min.h>static double (*nrfunc) (double);double fn1(double x, void *params){ double val = nrfunc(x); return val;}#define MAXITER 100/* Returns the minimum betwen ax and cx to a given tolerance tol using brent's method. */double brent(double ax, double bx, double cx, double (*f) (double), double tol, double *xmin){ int status; int iter = 0; double a, b, c; /* a < b < c */ const gsl_min_fminimizer_type *T; gsl_min_fminimizer *s; gsl_function F; /* gsl wants a<b */ b = bx; if(ax < cx) { a = ax; c = cx; } else { a = ax; c = cx; } /* if a-b < tol, return func(a) */ if(fabs(c - a) < tol) { *xmin = ax; return (f(*xmin)); } nrfunc = f; F.function = &fn1; F.params = 0; T = gsl_min_fminimizer_brent; s = gsl_min_fminimizer_alloc(T); gsl_min_fminimizer_set(s, &F, b, a, c); do { iter++; status = gsl_min_fminimizer_iterate(s); if(status) break; /* solver problem */ b = gsl_min_fminimizer_minimum(s); /* this is deprecated: we should use gsl_min_fminimizer_x_minimum(s) instead */ a = gsl_min_fminimizer_x_lower(s); c = gsl_min_fminimizer_x_upper(s); /* we should think about the tolerance more carefully... */ status = gsl_min_test_interval(a, c, tol, tol); } while(status == GSL_CONTINUE && iter < MAXITER); if(status != GSL_SUCCESS) Msg(GERROR, "MIN1D not converged: f(%g) = %g", b, fn1(b, NULL)); *xmin = b; gsl_min_fminimizer_free(s); return fn1(b, NULL);}/* Find an initial bracketting of the minimum of func. Given 2 initial points ax and bx, mnbrak checks in which direction func decreases, and takes some steps in that direction, until the function increases--at cx. mnbrak returns ax and cx (possibly switched), bracketting a minimum. */#define MYGOLD_ 1.618034#define MYLIMIT_ 100.0#define MYTINY_ 1.0e-20void mnbrak(double *ax, double *bx, double *cx, double *fa_dummy, double *fb_dummy, double *fc_dummy, double (*func) (double)){ double ulim, u, r, q; double tmp; volatile double f_a, f_b, f_c, f_u; f_a = (*func) (*ax); f_b = (*func) (*bx); if(f_b > f_a) { tmp = *ax; *ax = *bx; *bx = tmp; tmp = f_b; f_b = f_a; f_a = tmp; } *cx = *bx + MYGOLD_ * (*bx - *ax); f_c = (*func) (*cx); while(f_b > f_c) { r = (*bx - *ax) * (f_b - f_c); q = (*bx - *cx) * (f_b - f_a); u = (*bx) - ((*bx - *cx) * q - (*bx - *ax) * r) / (2.0 * SIGN(MAX(fabs(q - r), MYTINY_), q - r)); ulim = *bx + MYLIMIT_ * (*cx - *bx); if((*bx - u) * (u - *cx) > 0.0) { f_u = (*func) (u); if(f_u < f_c) { *ax = *bx; *bx = u; return; } else if(f_u > f_b) { *cx = u; return; } u = *cx + MYGOLD_ * (*cx - *bx); f_u = (*func) (u); } else if((*cx - u) * (u - ulim) > 0.0) { f_u = (*func) (u); if(f_u < f_c) { *bx = *cx; *cx = u; u = *cx + MYGOLD_ * (*cx - *bx); f_b = f_c; f_c = f_u; f_u = (*func) (u); } } else if((u - ulim) * (ulim - *cx) >= 0.0) { u = ulim; f_u = (*func) (u); } else { u = *cx + MYGOLD_ * (*cx - *bx); f_u = (*func) (u); } *ax = *bx; *bx = *cx; *cx = u; f_a = f_b; f_b = f_c; f_c = f_u; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -