[R] Is there a bisection method in R?

Matt Shotwell shotwelm at musc.edu
Mon Sep 20 21:09:31 CEST 2010


I was just reading about the merge sort algorithm last night (BTW, here
is a fun link http://www.youtube.com/watch?v=t8g-iYGHpEA). There are
some interesting similarities in this context. Here's a recursive method
for bisection:

bisectMatt <- function(fn, lo, hi, tol = 1e-7, ...) {

    flo <- fn(lo, ...)
    fhi <- fn(hi, ...)

    if(flo * fhi > 0)
        stop("root is not bracketed by lo and hi")

    mid <- (lo + hi) / 2
    fmid <- fn(mid, ...)
    if(abs(fmid) <= tol || abs(hi-lo) <= tol)
        return(mid)


    if(fmid * fhi > 0)
        return(bisectMatt(fn, lo, mid, tol, ...))

    return(bisectMatt(fn, mid, hi, tol, ...))
} 

# Adapted from Ravi's original
bisectRavi <- function(fn, lo, hi, tol = 1e-7, ...) {

    flo <- fn(lo, ...) 
    fhi <- fn(hi, ...) 

    if (flo * fhi > 0) 
        stop("root is not bracketed by lo and hi")

    chg <- hi - lo
    while (abs(chg) > tol) {
        mid <- (lo + hi) / 2
        fmid <- fn(mid, ...)
        if (abs(fmid) <= tol) break
        if (flo * fmid < 0) hi <- mid 
        if (fhi * fmid < 0) lo <- mid
        chg <- hi - lo
    }

    return(mid)
}

testFn <- function(x, a) exp(-x) - a*x 

> system.time(bM <- bisectMatt(testFn, 0, 2, a=1))
   user  system elapsed 
  0.000   0.000   0.001 

> system.time(bR <- bisectRavi(testFn, 0, 2, a=1))
   user  system elapsed 
  0.000   0.000   0.001 

> bM
[1] 0.5671433

> bR
[1] 0.5671433

Of course, Ravi's version is better for production (and most likely
faster, though not significantly so in this example) because recursion
is more expensive than looping.

-Matt

On Fri, 2010-09-17 at 17:44 -0400, Ravi Varadhan wrote:
> Here is something simple (does not have any checks for bad input), yet
> should be adequate:
> 
> bisect <- function(fn, lower, upper, tol=1.e-07, ...) {
> f.lo <- fn(lower, ...) 
> f.hi <- fn(upper, ...) 
> feval <- 2
> 
> if (f.lo * f.hi > 0) stop("Root is not bracketed in the specified interval
> \n")
> chg <- upper - lower
> 
> while (abs(chg) > tol) {
> 	x.new <- (lower + upper) / 2
> 	f.new <- fn(x.new, ...)
> 	if (abs(f.new) <= tol) break
> 	if (f.lo * f.new < 0) upper <- x.new 
> 	if (f.hi * f.new < 0) lower <- x.new 
> 	chg <- upper - lower
> 	feval <- feval + 1
> }
> list(x = x.new, value = f.new, fevals=feval)
> }
> 
> # An example
> fn1 <- function(x, a) {
> exp(-x) - a*x 
> }
> 
> bisect(fn1, 0, 2, a=1)
>  
> bisect(fn1, 0, 2, a=2)
> 
> 
> Ravi.
> 
> -----Original Message-----
> From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On
> Behalf Of Peter Dalgaard
> Sent: Friday, September 17, 2010 4:16 PM
> To: Gregory Gentlemen
> Cc: r-help at r-project.org
> Subject: Re: [R] Is there a bisection method in R?
> 
> On 09/17/2010 09:28 PM, Gregory Gentlemen wrote:
> > If uniroot is not a bisection method, then what function in R does use
> bisection?
> > 
> 
> Why do you assume that there is one? uniroot contains a better algorithm
> for finding bracketed roots.
> 
> It shouldn't be too hard to roll your own if you need one for
> pedagogical purposes.
> 

-- 
Matthew S. Shotwell
Graduate Student 
Division of Biostatistics and Epidemiology
Medical University of South Carolina



More information about the R-help mailing list