Find a zero of the function in the given interval to within a tolerance , where is the relative machine precision defined as the smallest representable number such that .
Note
This method ignores the value of atol
.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(brent_solver), | intent(inout) | :: | me | |||
real(kind=wp), | intent(in) | :: | ax |
left endpoint of initial interval |
||
real(kind=wp), | intent(in) | :: | bx |
right endpoint of initial interval |
||
real(kind=wp), | intent(in) | :: | fax |
|
||
real(kind=wp), | intent(in) | :: | fbx |
|
||
real(kind=wp), | intent(out) | :: | xzero |
abscissa approximating a zero of |
||
real(kind=wp), | intent(out) | :: | fzero |
value of |
||
integer, | intent(out) | :: | iflag |
status flag ( |
subroutine brent(me,ax,bx,fax,fbx,xzero,fzero,iflag) implicit none class(brent_solver),intent(inout) :: me real(wp),intent(in) :: ax !! left endpoint of initial interval real(wp),intent(in) :: bx !! right endpoint of initial interval real(wp),intent(in) :: fax !! `f(ax)` real(wp),intent(in) :: fbx !! `f(ax)` real(wp),intent(out) :: xzero !! abscissa approximating a zero of `f` in the interval `ax`,`bx` real(wp),intent(out) :: fzero !! value of `f` at the root (`f(xzero)`) integer,intent(out) :: iflag !! status flag (`0`=root found) real(wp),parameter :: eps = epsilon(1.0_wp) !! d1mach(4) in original code real(wp) :: a,b,c,d,e,fa,fb,fc,tol1,xm,p,q,r,s integer :: i !! iteration counter ! initialize: iflag = 0 tol1 = eps+1.0_wp a = ax b = bx fa = fax fb = fbx c = a fc = fa d = b-a e = d do i=1,me%maxiter if (abs(fc)<abs(fb)) then a=b b=c c=a fa=fb fb=fc fc=fa end if tol1 = 2.0_wp*eps*abs(b)+0.5_wp*me%rtol xm = 0.5_wp*(c-b) if (abs(xm)<=tol1) exit ! see if a bisection is forced if ((abs(e)>=tol1) .and. (abs(fa)>abs(fb))) then s=fb/fa if (a/=c) then ! inverse quadratic interpolation q=fa/fc r=fb/fc p=s*(2.0_wp*xm*q*(q-r)-(b-a)*(r-1.0_wp)) q=(q-1.0_wp)*(r-1.0_wp)*(s-1.0_wp) else ! linear interpolation p=2.0_wp*xm*s q=1.0_wp-s end if if (p<=0.0_wp) then p=-p else q=-q end if s=e e=d if (((2.0_wp*p)>=(3.0_wp*xm*q-abs(tol1*q))) .or. (p>=abs(0.5_wp*s*q))) then d=xm e=d else d=p/q end if else d=xm e=d end if a=b fa=fb if (abs(d)<=tol1) then if (xm<=0.0_wp) then b=b-tol1 else b=b+tol1 end if else b=b+d end if fb=me%f(b) if (abs(fb)<=me%ftol) exit ! absolute convergence in f if ((fb*(fc/abs(fc)))>0.0_wp) then c=a fc=fa d=b-a e=d end if if (i==me%maxiter) iflag = -2 ! max iterations reached end do xzero = b fzero = fb end subroutine brent