80 lines
1.5 KiB
C++
80 lines
1.5 KiB
C++
#include <cmath>
|
|
#include <limits>
|
|
#include "nr.h"
|
|
using namespace std;
|
|
|
|
namespace {
|
|
inline void shft3(DP &a, DP &b, DP &c, const DP d)
|
|
{
|
|
a=b;
|
|
b=c;
|
|
c=d;
|
|
}
|
|
}
|
|
|
|
DP NR::brent(const DP ax, const DP bx, const DP cx, DP f(const DP),
|
|
const DP tol, DP &xmin)
|
|
{
|
|
const int ITMAX=100;
|
|
const DP CGOLD=0.3819660;
|
|
const DP ZEPS=numeric_limits<DP>::epsilon()*1.0e-3;
|
|
int iter;
|
|
DP a,b,d=0.0,etemp,fu,fv,fw,fx;
|
|
DP p,q,r,tol1,tol2,u,v,w,x,xm;
|
|
DP e=0.0;
|
|
|
|
a=(ax < cx ? ax : cx);
|
|
b=(ax > cx ? ax : cx);
|
|
x=w=v=bx;
|
|
fw=fv=fx=f(x);
|
|
for (iter=0;iter<ITMAX;iter++) {
|
|
xm=0.5*(a+b);
|
|
tol2=2.0*(tol1=tol*fabs(x)+ZEPS);
|
|
if (fabs(x-xm) <= (tol2-0.5*(b-a))) {
|
|
xmin=x;
|
|
return fx;
|
|
}
|
|
if (fabs(e) > tol1) {
|
|
r=(x-w)*(fx-fv);
|
|
q=(x-v)*(fx-fw);
|
|
p=(x-v)*q-(x-w)*r;
|
|
q=2.0*(q-r);
|
|
if (q > 0.0) p = -p;
|
|
q=fabs(q);
|
|
etemp=e;
|
|
e=d;
|
|
if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x))
|
|
d=CGOLD*(e=(x >= xm ? a-x : b-x));
|
|
else {
|
|
d=p/q;
|
|
u=x+d;
|
|
if (u-a < tol2 || b-u < tol2)
|
|
d=SIGN(tol1,xm-x);
|
|
}
|
|
} else {
|
|
d=CGOLD*(e=(x >= xm ? a-x : b-x));
|
|
}
|
|
u=(fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d));
|
|
fu=f(u);
|
|
if (fu <= fx) {
|
|
if (u >= x) a=x; else b=x;
|
|
shft3(v,w,x,u);
|
|
shft3(fv,fw,fx,fu);
|
|
} else {
|
|
if (u < x) a=u; else b=u;
|
|
if (fu <= fw || w == x) {
|
|
v=w;
|
|
w=u;
|
|
fv=fw;
|
|
fw=fu;
|
|
} else if (fu <= fv || v == x || v == w) {
|
|
v=u;
|
|
fv=fu;
|
|
}
|
|
}
|
|
}
|
|
nrerror("Too many iterations in brent");
|
|
xmin=x;
|
|
return fx;
|
|
}
|