# unirootR: One Dimensional Root (Zero) Finding - in pure R In Rmpfr: R MPFR - Multiple Precision Floating-Point Reliable

## Description

The function `unirootR` searches the interval from `lower` to `upper` for a root (i.e., zero) of the function `f` with respect to its first argument.

`unirootR()` is “clone” of `uniroot()`, written entirely in R, in a way that it works with `mpfr`-numbers as well.

## Usage

 ```1 2 3 4 5 6``` ```unirootR(f, interval, ..., lower = min(interval), upper = max(interval), f.lower = f(lower, ...), f.upper = f(upper, ...), verbose = FALSE, tol = .Machine\$double.eps^0.25, maxiter = 1000, epsC = NULL) ```

## Arguments

 `f` the function for which the root is sought. `interval` a vector containing the end-points of the interval to be searched for the root. `...` additional named or unnamed arguments to be passed to `f` `lower, upper` the lower and upper end points of the interval to be searched. `f.lower, f.upper` the same as `f(upper)` and `f(lower)`, respectively. Passing these values from the caller where they are often known is more economical as soon as `f()` contains non-trivial computations. `verbose` logical (or integer) indicating if (and how much) verbose output should be produced during the iterations. `tol` the desired accuracy (convergence tolerance). `maxiter` the maximum number of iterations. `epsC` positive number or `NULL` in which case a smart default is sought. This should specify the “achievable machine precision” for the given numbers and their arithmetic. The default will set this to `.Machine\$double.eps` for double precision numbers, and will basically use `2 ^ - min(getPrec(f.lower), getPrec(f.upper))` when that works (as, e.g., for `mpfr`-numbers) otherwise. This is factually a lower bound for the achievable lower bound, and hence, setting `tol` smaller than `epsC` is typically non-sensical sense and produces a warning.

## Details

Note that arguments after `...` must be matched exactly.

Either `interval` or both `lower` and `upper` must be specified: the upper endpoint must be strictly larger than the lower endpoint. The function values at the endpoints must be of opposite signs (or zero).

The function only uses R code with basic arithmetic, such that it should also work with “generalized” numbers (such as `mpfr`-numbers) as long the necessary `Ops` methods are defined for those.

The underlying algorithm assumes a continuous function (which then is known to have at least one root in the interval).

Convergence is declared either if `f(x) == 0` or the change in `x` for one step of the algorithm is less than `tol` (plus an allowance for representation error in `x`).

If the algorithm does not converge in `maxiter` steps, a warning is printed and the current approximation is returned.

`f` will be called as `f(x, ...)` for a (generalized) numeric value of x.

## Value

A list with four components: `root` and `f.root` give the location of the root and the value of the function evaluated at that point. `iter` and `estim.prec` give the number of iterations used and an approximate estimated precision for `root`. (If the root occurs at one of the endpoints, the estimated precision is `NA`.)

## Source

Based on `zeroin()` (in package rootoned) by John Nash who manually translated the C code in R's `zeroin.c` and on `uniroot()` in R's sources.

## References

Brent, R. (1973), see `uniroot`.

`polyroot` for all complex roots of a polynomial; `optimize`, `nlm`.
 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46``` ```require(utils) # for str ## some platforms hit zero exactly on the first step: ## if so the estimated precision is 2/3. f <- function (x,a) x - a str(xmin <- unirootR(f, c(0, 1), tol = 0.0001, a = 1/3)) ## handheld calculator example: fixpoint of cos(.): rc <- unirootR(function(x) cos(x) - x, lower=-pi, upper=pi, tol = 1e-9) rc\$root ## the same with much higher precision: rcM <- unirootR(function(x) cos(x) - x, interval= mpfr(c(-3,3), 300), tol = 1e-40) rcM x0 <- rcM\$root stopifnot(all.equal(cos(x0), x0, tol = 1e-40))## 40 digits accurate! str(unirootR(function(x) x*(x^2-1) + .5, lower = -2, upper = 2, tol = 0.0001), digits.d = 10) str(unirootR(function(x) x*(x^2-1) + .5, lower = -2, upper = 2, tol = 1e-10 ), digits.d = 10) ## A sign change of f(.), but not a zero but rather a "pole": tan. <- function(x) tan(x * (Const("pi",200)/180))# == tan( ) (rtan <- unirootR(tan., interval = mpfr(c(80,100), 200), tol = 1e-40)) ## finds 90 {"ok"}, and now gives a warning ## Find the smallest value x for which exp(x) > 0 (numerically): r <- unirootR(function(x) 1e80*exp(x)-1e-300, c(-1000,0), tol = 1e-15) str(r, digits.d = 15) ##> around -745, depending on the platform. exp(r\$root) # = 0, but not for r\$root * 0.999... minexp <- r\$root * (1 - 10*.Machine\$double.eps) exp(minexp) # typically denormalized ## --- using mpfr-numbers : ## Find the smallest value x for which exp(x) > 0 ("numerically"); ## Note that mpfr-numbers underflow *MUCH* later than doubles: ## one of the smallest mpfr-numbers {see also ?mpfr-class } : (ep.M <- mpfr(2, 55) ^ - ((2^30 + 1) * (1 - 1e-15))) r <- unirootR(function(x) 1e99* exp(x) - ep.M, mpfr(c(-1e20, 0), 200)) r # 97 iterations; f.root is very similar to ep.M ```