%\documentclass[article]{jss} \documentclass[nojss,article]{jss} % ----- for the package-vignette, don't use JSS logo, etc % %__FIXME: use ..\index{} for a good "reference index" about the things we show! % \author{Martin M\"achler \\ ETH Zurich} \title{Arbitrarily Accurate Computation with \R: \\ The \pkg{Rmpfr} Package} % \def\mythanks{a version of this paper, for \pkg{nacopula} 0.4\_4, has been published % in JSS, \url{http://www.jstatsoft.org/v39/i09}.} %% for pretty printing and a nice hypersummary also set: \Plainauthor{Martin M\"achler} %% comma-separated \Plaintitle{Arbitrarily Accurate Computation with R---The Rmpfr Package} % \Shorttitle{} % % The index entry makes it into build/vignette.rds : %\VignetteIndexEntry{Arbitrarily Accurate Computation with R Package Rmpfr} %\VignetteDepends{Rmpfr} %\VignetteDepends{gmp} %\VignetteDepends{Bessel} \SweaveOpts{engine=R,eps=FALSE,pdf=TRUE,width=7,height=4,strip.white=true,keep.source=TRUE} %% an abstract and keywords \Abstract{ The \R\ package \pkg{Rmpfr} allows to use arbitrarily precise numbers instead of \R's double precision numbers in many \R\ computations and functions. %% This is achieved by defining S4 classes of such numbers and vectors, matrices, and arrays thereof, where all arithmetic and mathematical functions work via the (GNU) MPFR C library, where MPFR is acronym for ``\emph{\textbf{M}ultiple \textbf{P}recision \textbf{F}loating-Point \textbf{R}eliably}''. MPFR is Free Software, available under the LGPL license, and itself is built on the free GNU Multiple Precision arithmetic library (GMP). Consequently, by using \pkg{Rmpfr}, you can often call your \R\ function or numerical code with mpfr--numbers instead of simple numbers, and all results will automatically be much more accurate. %% see subsection{Applications} further below: Applications by the package author include testing of Bessel or polylog functions and distribution computations, e.g. for ($\alpha$-)stable distributions and Archimedean Copulas. %% In addition, the \pkg{Rmpfr} has been used on the \code{R-help} or \code{R-devel} mailing list for high-accuracy computations, e.g., in comparison with results from other software, and also in improving existing \R\ functionality, e.g., fixing \R\ bug \href{https://bugs.R-project.org/bugzilla3/show_bug.cgi?id=14491}{\code{PR\#14491}}. } \Keywords{MPFR, Abitrary Precision, Multiple Precision Floating-Point, R} %% at least one keyword must be supplied %% publication information %% NOTE: Typically, this can be left commented and will be filled out by the technical editor %% \Volume{13} %% \Issue{9} %% \Month{September} %% \Year{2004} %% \Submitdate{2004-09-29} %% \Acceptdate{2004-09-29} %% The address of (at least) one author should be given %% in the following format: \Address{ Martin M\"achler\\ Seminar f\"ur Statistik, HG G~16\\ ETH Zurich\\ 8092 Zurich, Switzerland\\ E-mail: \email{maechler@stat.math.ethz.ch}\\ URL: \url{http://stat.ethz.ch/people/maechler} } %% It is also possible to add a telephone and fax number %% before the e-mail in the following format: %% Telephone: +43/1/31336-5053 %% Fax: +43/1/31336-734 %% for those who use Sweave please include the following line (with % symbols): %% MM: this is "substituted" by jss.cls: %% need no \usepackage{Sweave.sty} %% Marius' packages \usepackage[american]{babel}%for American English % \usepackage{microtype}%for character protrusion and font expansion (only with pdflatex) \usepackage{amsmath}%sophisticated mathematical formulas with amstex (includes \text{}) \usepackage{mathtools}%fix amsmath deficiencies \usepackage{amssymb}%sophisticated mathematical symbols with amstex (includes \mathbb{}) % \usepackage{amsthm}%theorem environments % \usepackage{bm}%for bold math symbols: \bm (= bold math) % %NON-STANDARD:\RequirePackage{bbm}%only for indicator functions % \usepackage{enumitem}%for automatic numbering of new enumerate environments % \usepackage[ % format=hang, % % NOT for JSS: labelsep=space, % justification=justified, % singlelinecheck=false%, % % NOT for JSS: labelfont=bf % ]{caption}%for captions % \usepackage{tikz}%sophisticated graphics package % \usepackage{tabularx}%for special table environment (tabularx-table) % \usepackage{booktabs}%for table layout % This is already in jss above -- but withOUT the fontsize=\small part !! \DefineVerbatimEnvironment{Sinput}{Verbatim}{fontsize=\small,fontshape=sl} \DefineVerbatimEnvironment{Soutput}{Verbatim}{fontsize=\small} \DefineVerbatimEnvironment{Scode}{Verbatim}{fontsize=\small,fontshape=sl} % but when submitting, do get rid of too much vertical space between R % input & output, i.e. between Sinput and Soutput: \fvset{listparameters={\setlength{\topsep}{0pt}}}% !! quite an effect! %% % \newcommand*{\R}{\proglang{R}}%{\textsf{R}} \newcommand*{\Arg}[1]{\texttt{\itshape $\langle$#1$\rangle$}} \newcommand*{\eps}{\varepsilon} \newcommand*{\CRANpkg}[1]{\href{http://CRAN.R-project.org/package=#1}{\pkg{#1}}} %% end of declarations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document} %% include your article here, just as usual %% Note that you should use the \pkg{}, \proglang{} and \code{} commands. % \section[About Java]{About \proglang{Java}} %% Note: If there is markup in \(sub)section, then it has to be escape as above. %% Note: These are explained in '?RweaveLatex' : <>= options(SweaveHooks= list(fig=function() par(mar=c(5.1, 4.1, 1.1, 2.1))), width = 75, digits = 7, # <-- here, keep R's default! prompt = "R> ", continue=" ") Sys.setenv(LANGUAGE = "en") if(.Platform$OS.type != "windows") Sys.setlocale("LC_MESSAGES","C") <>= if(nzchar(Sys.getenv("R_MM_PKG_CHECKING"))) print( .libPaths() ) stopifnot(require("sfsmisc")) @ \section[Introduction]{Introduction}% \small~\footnote{\mythanks}} %% - Why did I want this in R : There are situations, notably in researching better numerical algorithms for non-trivial mathematical functions, say the $F$-distribution function, where it is interesting and very useful to be able to rerun computations in \R\ in (potentially much) higher precision. For example, if you are interested in Euler's $e$, the base of natural logarithms, and given, e.g., by $e^x = \exp(x)$, you will look into <>= exp(1) @ which typically uses 7 digits for printing, as \code{getOption("digits")} is 7. To see \R's internal accuracy fully, you can use <>= print(exp(1), digits = 17) @ With \pkg{Rmpfr} you can now simply use ``mpfr -- numbers'' and get more accurate results automatically, here using a \emph{vector} of numbers as is customary in \R: <>= require("Rmpfr") # after having installed the package ... (one <- mpfr(1, 120)) exp(one) @ In combinatorics, number theory or when computing series, you may occasionally want to work with \emph{exact} factorials or binomial coefficients, where e.g. you may need all factorials $k!$, for $k=1,2,\dots,24$ or a full row of Pascal's triangle, i.e., want all $\binom{n}{k}$ for $n=80$. With \R's double precision, and standard printing precision <>= ns <- 1:24 ; factorial(ns) @ the full precision of $24!$ is clearly not printed. However, if you display it with more than its full internal precision, <>= noquote(sprintf("%-30.0f", factorial(24))) @ it is obviously wrong in the last couple of digits as they are known to be \code{0}. However, you can easily get full precision results with \pkg{Rmpfr}, by replacing ``simple'' numbers by mpfr-numbers: <>= ns <- mpfr(1:24, 120) ; factorial(ns) @ Or for the 80-th Pascal triangle row, $\binom{n}{k}$ for $n=80$ and $k=1,\dots,n$, <>= chooseMpfr.all(n = 80) <>= capture.and.write(# <- in package 'sfsmisc': ~/R/Pkgs/sfsmisc/R/misc-goodies.R <> , 5, 2, middle = 4, i.middle = 13) @ %%% "FIXME:" drawback of the above is that it is *integer* arithmetic only ... \paragraph{S4 classes and methods:} % Why they are useful here: S4 allows ``multiple dispatch'' which means that the method that is called for a generic function may not just depend on the first argument of the function (as in S3 or in traditional class-based OOP), but on a \emph{``signature''} of multiple arguments. For example, \texttt{a + b} is the same as \code{`+`(a,b)}, i.e., calling a function with two arguments. ... \subsection{The engine behind: MPFR and GMP} The package \pkg{Rmpfr} interfaces \R\ to the C (GNU) library \begin{quote} MPFR, acronym for ``\emph{\textbf{M}ultiple \textbf{P}recision \textbf{F}loating-Point \textbf{R}eliably}'' \end{quote} MPFR is Free Software, available under the LGPL license, %\nocite{ see \url{http://mpfr.org/} and \cite{FouLHLPZ:2007} and the standard reference to MPFR, \cite{FousseHLPZ-MPFR:2011}. %% MPFR itself is built on and requires the GNU Multiple Precision arithmetic library (GMP), see \url{http://gmplib.org/} and \cite{GMP:2011}. It can be obtained from there, or from your operating system vendor. On some platforms, it is very simple, to install MPFR and GMP, something necessary before \pkg{Rmpfr} can be used. E.g., in Linux distributions Debian, Ubuntu and other Debian derivatives, it is sufficient (for \emph{both} libraries) to simply issue \begin{verbatim} sudo apt-get install libmpfr-dev \end{verbatim} \section{Arithmetic with mpfr-numbers} <>= (0:7) / 7 # k/7, for k= 0..7 printed with R's default precision options(digits= 16) (0:7) / 7 # in full double precision accuracy options(digits= 7) # back to default str(.Machine[c("double.digits","double.eps", "double.neg.eps")], digits=10) 2^-(52:53) @ In other words, the double precision numbers \R\ uses have a 53-bit mantissa, and the two ``computer epsilons'' are $2^{-52}$ and $2^{-53}$, respectively. Less technically, how many decimal digits can double precision numbers work with, $2^{-53} = 10^{-x} \Longleftrightarrow x = 53 \log_{10}(2)$, <>= 53 * log10(2) @ i.e., almost 16 digits. If we want to compute some arithmetic expression with higher precision, this can now easily be achieved, using the \pkg{Rmpfr} package, by defining ``\texttt{mpfr}--numbers'' and then work with these. Starting with simple examples, a more precise version of $k/7$, $k = 0,\dots, 7$ from above: <>= x <- mpfr(0:7, 80)/7 # using 80 bits precision x 7*x 7*x - 0:7 @ which here is even ``perfect'' -- but that's ``luck'' only, and also the case here for ``simple'' double precision numbers, at least on our current platform.\footnote{64-bit Linux, Fedora 13 on a ``AMD Phenom 925'' processor} \subsection[Mathematical Constants, Pi, gamma, ..]{% Mathematical Constants, Pi ($\pi$), gamma, etc} Our \pkg{Rmpfr} package also provides the mathematical constants which MPFR provides, via \code{Const(., \Arg{prec})}, currently the \Sexpr{length(eval(formals(Const)[["name"]]))} constants <>= formals(Const)$name @ are available, where \code{"gamma"} is for Euler's gamma, $\gamma := \lim_{n\to\infty} \sum_{k=1}^n \frac 1 k - \log(n) \approx 0.5777$, and \code{"catalan"} for Catalan's constant (see \url{http://en.wikipedia.org/wiki/Catalan\%27s_constant}). <>= Const("pi") Const("log2") @ where you may note a default precision of 120 digits, a bit more than quadruple precision, but also that 1000 digits of $\pi$ are available instantaneously, <>= system.time(Pi <- Const("pi", 1000 *log2(10))) Pi @ As nice example of using Mpfr arithmetic: On a wintery Sunday, Hans Borchers desired to have an exact $\pi$ constant in \pkg{Rmpfr}, and realized that of course \code{mpfr(pi, 256)} could not be the solution, as \code{pi} is the double precision version of $\pi$ and hence only about 53 bit accurate (and the \code{mpfr()} cannot do magic, recognizing ``symbolic'' $\pi$). As he overlooked the \code{Const("pi", .)} solution above, he implemented the following function that computes pi applying Gauss' spectacular AGM-based (AGM := Arithmetic-Geometric Mean) approach [Borwein and Borwein (1987), \emph{Pi and the AGM}]; I have added a \code{verbose} argument, explicit iteration counting and slightly adapted the style to my own: <>= piMpfr <- function(prec=256, itermax = 100, verbose=TRUE) { m2 <- mpfr(2, prec) # '2' as mpfr number ## -> all derived numbers are mpfr (with precision 'prec') p <- m2 + sqrt(m2) # 2 + sqrt(2) = 3.414.. y <- sqrt(sqrt(m2)) # 2^ {1/4} x <- (y+1/y) / m2 it <- 0L repeat { p.old <- p it <- it+1L p <- p * (1+x) / (1+y) if(verbose) cat(sprintf("it=%2d, pi^ = %s, |.-.|/|.|=%e\n", it, formatMpfr(p, min(50, prec/log2(10))), 1-p.old/p)) if (abs(p-p.old) <= m2^(-prec)) break if(it > itermax) { warning("not converged in", it, "iterations") ; break } ## else s <- sqrt(x) y <- (y*s + 1/s) / (1+y) x <- (s+1/s)/2 } p } piMpfr()# indeed converges *quadratically* fast ## with relative error relErr <- 1 - piMpfr(256, verbose=FALSE) / Const("pi",260) ## in bits : asNumeric(-log2(abs(relErr))) @ \subsection[{seqMpfr()} for sequences:]{\code{seqMpfr()} for sequences:} In \R, arithmetic sequences are constructed by \code{seq()}, the ``sequence'' function, which is not generic, and with its many ways and possible arguments is convenient, but straightforward to automatically generalize for mpfr numbers. Instead, we provide the \code{seqMpfr} function... \subsection[Rounding, {roundMpfr()}, {asNumeric()} etc:]{% Rounding, \code{roundMpfr()}, \code{asNumeric()} etc:} In \R, the \code{round()} and \code{signif()} functions belong to the \code{Math2} group, and we provide \code{"mpfr"}-class methods for them: <>= getGroupMembers("Math2") showMethods("Math2", classes=c("mpfr", "mpfrArray")) @ For consistency reasons, however the resulting numbers keep the same number of precision bits, \code{precBits}: <>= i7 <- 1/mpfr(700, 100) c(i7, round(i7, digits = 6), signif(i7, digits = 6)) @ If you really want to ``truncate'' the precision to less digits or bits, you call \code{roundMpfr()}, <>= roundMpfr(i7, precBits = 30) roundMpfr(i7, precBits = 15) @ Note that 15 bits correspond to approximately $15 \cdot 0.3$, i.e., 4.5 digits, because $1/\log_2(10) \approx 0.30103\dots$. \paragraph{asNumeric():} Often used, e.g., to return to fast (\R-internal) arithmetic, also as alternative to \code{roundMpfr()} is to ``round to double precision'' producing standard \R numbers from ``mpfr'' numbers. We provide the function \code{asNumeric()}, a generic function with methods also for \code{"mpfrArray"} see below and the big integers and big rationals from package \pkg{gmp}, <>= showMethods(asNumeric) @ see, e.g., its use above. \paragraph{Formatting:} For explicit printing or plotting purposes, we provide an \code{"mpfr"} method for \R's \code{format()} function, also as explicit utility function \code{formatMpfr(x, digits)} which provides results to \code{digits} \emph{significant} digits, <>= cbind( sapply(1:7, function(d) format(i7, digits=d)) ) @ There, \code{digits = NULL} is the default where the help has (``always'') promised \emph{The default, \code{NULL}, uses enough digits to represent the full precision, often one or two digits more than you would expect}. However, for large numbers, say $10^{20000}$, e.g., \Sexpr{x <- mpfr(10,80)^20000}, all of \code{formatMpfr(x)}, \code{format(x)}, and \code{print(x)} (including ``auto-printing'' of \code{x}), have shown all digits \emph{before} the decimal point and not at all taken into account the 80-bit precision of \code{x} (which corresponds to only \code{80 / log2(10)} $\approx 24$ decimal digits). This has finally changed in the (typically default) case \code{formatMpfr(*, maybe.full = FALSE)}: <>= x <- mpfr(2, 80) ^ ((1:4)*10000) cbind(x) # -> show() -> print.mpfr() -> formatMpfr(.. , digits = NULL, maybe.full = FALSE) nchar(formatMpfr(x)) nchar(formatMpfr(x, maybe.full = TRUE)) @ \section{``All'' mathematical functions, arbitrarily precise} %% see ../../man/mfpr-class.Rd %% but also .... %% {Math}{\code{signature(x = "mpfr")}: All the S4 ``\texttt{Math}'' group functions are defined, using multiple precision (MPFR) arithmetic, i.e., <>= getGroupMembers("Math") @ % \code{{abs}}, \code{{sign}}, \code{{sqrt}}, % \code{{ceiling}}, \code{{floor}}, \code{{trunc}}, % \code{{cummax}}, \code{{cummin}}, \code{{cumprod}}, % \code{{cumsum}}, \code{{exp}}, \code{{expm1}}, % \code{{log}}, \code{{log10}}, \code{{log2}}, % \code{{log1p}}, \code{{cos}}, \code{{cosh}}, % \code{{sin}}, \code{{sinh}}, \code{{tan}}, % \code{{tanh}}, \code{{acos}}, \code{{acosh}}, % \code{{asin}}, \code{{asinh}}, \code{{atan}}, % \code{{atanh}}, \code{{gamma}}, \code{{lgamma}}, % \code{{digamma}}, and \code{{trigamma}}. where currently, \code{trigamma} is not provided by the MPFR library, and hence not implemented yet. %% cumsum(), cumprod() now work! \code{factorial()} has a \texttt{"mpfr"} method; and in addition, \code{factorialMpfr()} computes ${n!}$ efficiently in arbitrary precision, using the MPFR-internal implementation. This is mathematically (but not numerically) the same as $\Gamma(n+1) = $\code{gamma(n+1)}. Similarly to \code{factorialMpfr()}, but more generally useful,the functions \code{chooseMpfr(a,n)} and \code{pochMpfr(a,n)} compute (generalized!) binomial coefficients $\binom{a}{n}$ and ``the'' Pochhammer symbol or ``rising factorial'' \begin{eqnarray*} a^{(n)} &:=& a(a+1)(a+2)\cdots(a+n-1) \\ &=& \frac{(a+n-1)!}{(a-1)!} = \frac{\Gamma(a+n)}{\Gamma(a)}. \end{eqnarray*} Note that with this definition, \[ \binom{a}{n} \equiv \frac{a^{(n)}}{n!}. \] \section{Arbitrarily precise matrices and arrays} %%% FIXME --> ~/R/Meetings-Kurse-etc/2011-Warwick/1_MM_/Poster/MM-poster.tex The classes \code{"mpfrMatrix"} and \code{"mpfrArray"} correspond to the classical numerical \R\ \code{"matrix"} and \code{"array"} objects, which basically are arrays or vectors of numbers with a dimension \code{dim}, possibly named by \code{dimnames}. As there, they can be constructed by \code{dim(.) <- ..} setting, e.g., <>= head(x <- mpfr(0:7, 64)/7) ; mx <- x dim(mx) <- c(4,2) @ or by the \code{mpfrArray()} constructor, <>= dim(aa <- mpfrArray(1:24, precBits = 80, dim = 2:4)) <>= aa <>= capture.and.write(aa, 11, 4) @ and we can index and multiply such matrices, e.g., <>= mx[ 1:3, ] + c(1,10,100) crossprod(mx) @ and also \code{apply} functions, <>= apply(7 * mx, 2, sum) @ \section{Special mathematical functions} \code{zeta(x)} computes Riemann's Zeta function $\zeta(x)$ important in analytical number theory and related fields. The traditional definition is \begin{equation*} \zeta(x) = \sum_{n=1}^\infty \frac{1}{n^x}. \end{equation*} \code{Ei(x)} computes the \textbf{e}xponential integral, \begin{equation*} \int_{-\infty}^{x} \frac{e^t}{t} \; dt. \end{equation*} <>= curve(Ei, 0, 5, n=2001); abline(h=0,v=0, lty=3) @ \code{Li2(x)}, part of the MPFR C library since version 2.4.0, computes the dilogarithm, \begin{equation*} \mathtt{Li2(x)} = \operatorname{Li}_2(x) := \int_{0}^{x} \frac{-log(1-t)}{t} \; dt, \end{equation*} which is the most prominent ``polylogarithm'' function, where the general polylogarithm is (initially) defined as \begin{equation*} \operatorname{Li}_s(z) = \sum_{k=1}^\infty \frac{z^k}{k^s}, \ \forall s \in \mathbb{C} \ \ \forall |z| < 1, z\in\mathbb{C}, \end{equation*} see \url{http://en.wikipedia.org/wiki/Polylogarithm#Dilogarithm}. Note that the integral definition is valid for all $x\in \mathbb{C}$, and also, $Li_2(1) = \zeta(2) = \pi^2/6$. <>= if(mpfrVersion() >= "2.4.0") ## Li2() is not available in older MPFR versions all.equal(Li2(1), Const("pi", 128)^2/6, tol = 1e-30) @ where we also see that \pkg{Rmpfr} provides \texttt{all.equal()} methods for mpfr-numbers which naturally allow very small tolerances \code{tol}. <>= if(mpfrVersion() >= "2.4.0") curve(Li2, -2, 13, n=2000); abline(h=0,v=0, lty=3) @ \code{erf(x)} is the ``error\footnote{named exactly because of its relation to the normal / Gaussian distribution} function'' and \code{erfc(x)} its \textbf{c}omplement, \code{erfc(x) := 1 - erf(x)}, defined as \begin{equation*} \operatorname{erf}(x) = \frac{2}{\sqrt{\pi}}\int_{0}^x e^{-t^2} dt, \end{equation*} and consequently, both functions simply are reparametrizations of the cumulative normal, $\Phi(x) = \int_{-\infty}^x \phi(t)\;dt = $\code{pnorm(x)} where $\phi$ is the normal density function $\phi(t) := \frac{1}{\sqrt{2\pi}}e^{-t^2}$=\code{dnorm(x)}. Namely, \code{erf(x) = 2*pnorm(sqrt(2)*x)} and \code{erfc(x) = 1 - erf(x) = 2* pnorm(sqrt(2)*x, lower=FALSE)}. <>= curve(erf, -3,3, col = "red", ylim = c(-1,2)) curve(erfc, add = TRUE, col = "blue") abline(h=0, v=0, lty=3); abline(v=c(-1,1), lty=3, lwd=.8, col="gray") legend(-3,1, c("erf(x)", "erfc(x)"), col = c("red","blue"), lty=1) @ \subsection{Applications} The CRAN package \CRANpkg{Bessel} provides asymptotic formulas for Bessel functions also of \emph{fractional} order which do work for \code{mpfr}-vector arguments as well. \section{Integration highly precisely} Sometimes, important functions are defined as integrals of other known functions, e.g., the dilogarithm $\operatorname{Li}_2()$ above. Consequently, we found it desirable to allow numerical integration, using mpfr-numbers, and hence---conceptionally---arbitrarily precisely. \R's \code{integrate()} uses a relatively smart adaptive integration scheme, but based on C code which is not very simply translatable to pure \R, to be used with mpfr numbers. For this reason, our \code{integrateR()} function uses classical Romberg integration \citep{Bauer-1961}. We demonstrate its use, first by looking at a situation where \R's \code{integrate()} can get problems: <>= integrateR(dnorm,0,2000) integrateR(dnorm,0,2000, rel.tol=1e-15) integrateR(dnorm,0,2000, rel.tol=1e-15, verbose=TRUE) @ Now, for situations where numerical integration would not be necessary, as the solution is known analytically, but hence are useful for exploration of high accuracy numerical integration: First, the exponential function $\exp(x) = e^x$ with its well-known $\int \exp(t)\;dt = \exp(x)$, both with standard (double precision) floats, <>= (Ie.d <- integrateR(exp, 0 , 1, rel.tol=1e-15, verbose=TRUE)) @ and then the same, using 200-bit accurate mpfr-numbers: <>= (Ie.m <- integrateR(exp, mpfr(0,200), 1, rel.tol=1e-25, verbose=TRUE)) (I.true <- exp(mpfr(1, 200)) - 1) ## with absolute errors as.numeric(c(I.true - Ie.d$value, I.true - Ie.m$value)) @ Now, for polynomials, where Romberg integration of the appropriate order is exact, mathematically, <>= if(require("polynom")) { x <- polynomial(0:1) p <- (x-2)^4 - 3*(x-3)^2 Fp <- as.function(p) print(pI <- integral(p)) # formally print(Itrue <- predict(pI, 5) - predict(pI, 0)) ## == 20 } else { Fp <- function(x) (x-2)^4 - 3*(x-3)^2 Itrue <- 20 } (Id <- integrateR(Fp, 0, 5)) (Im <- integrateR(Fp, 0, mpfr(5, 256), rel.tol = 1e-70, verbose=TRUE)) ## and the numerical errors, are indeed of the expected size: 256 * log10(2) # - expect ~ 77 digit accuracy for mpfr(*., 256) as.numeric(Itrue - c(Im$value, Id$value)) @ \section{Miscellaneous} For probability and density computations, it is known to be important in many contexts to work on the $\log$--scale, i.e., with log probabilities $\log P(.)$ or log densities $\log f()$. In \R{} itself, we (R Core) had introduced logical optional arguments \code{log} (for density) and \code{log.p} for probability (e.g., \code{pnorm()} and quantile (e.g., \code{qnorm}) functions. As our \code{pnorm()} is based on MPFR's \code{erf()} and \code{erfc()} which currently do \emph{not} have scaled versions, for \code{Rmpfr::pnorm(.., log.p=TRUE)} we do need to compute the logarithm (instead of working on the log scale). On the extreme left tail, \R{} correctly computes <>= pnorm(-1234, log.p=TRUE) @ i.e., \code{-761386.036955} to more digits. However, \code{erf()} and \code{erfc()} do not have a log scale or other scaled versions. Thanks to the large range of exponents compared to double precision numbers it does less quickly underflow to zero, e.g., <>= (p123 <- Rmpfr::pnorm(mpfr(-123, 66), log.p=TRUE)) # is based on (ec123 <- erfc(123 * sqrt(mpfr(0.5, 66+4))) / 2) # 1.95....e-3288 (p333 <- Rmpfr::pnorm(mpfr(-333, 66), log.p=TRUE)) exp(p333) stopifnot(p123 == log(roundMpfr(ec123, 66)), ## '==' as we implemented our pnorm() all.equal(p333, -55451.22709, tol=1e-8)) @ and indeed, the default range for exponent (wrt base 2, not 10) is given by <>= (old_erng <- .mpfr_erange() ) @ which shows the current minimal and maximal base-2 exponents for mpfr-numbers, by ``factory-fresh'' default, the number $-2^{30}$ and $2^{30}$, i.e., $\pm 1073741823$ which is much larger than the corresponding limits for regular double precision numbers, <>= unlist( .Machine[c("double.min.exp", "double.max.exp")] ) @ which are basically $\pm 2^{10}$; note that double arithmetic typically allows subnormal numbers which are even smaller than $2^{-1024}$, also in \R{}, on all usual platforms, <>= 2^(-1022 - 52) @ is equal to $2^{-1074}$ and the really smallest positive double precision number. Now, \emph{if} if the GMP library to which both \R{} package \pkg{gmp} and \pkg{Rmpfr} interface is built ``properly'', i.e., with full 64 bit ``numb''s, we can \emph{extend} the range of mpfr-numbers even further. By how much, we can read off <>= .mpfr_erange(.mpfr_erange_kinds) ## and then set # use very slightly smaller than extreme values: (myERng <- (1-2^-52) * .mpfr_erange(c("min.emin","max.emax"))) .mpfr_erange_set(value = myERng) # and to see what happened: .mpfr_erange() @ If that worked well, this shows \code{-/+ 4.611686e+18}, or actually $\mp 2^{62}$, \code{log2(abs(.mpfr_erange()))} giving \Sexpr{log2(abs(.mpfr_erange()))}. However, currently on Winbuilder this does not extend, notably as the GMP numbs, <>= .mpfr_gmp_numbbits() @ have \emph{not} been 64, there. \section{Conclusion} The \R\ package \pkg{Rmpfr}, available from CRAN since August 2009, provides the possibility to run many computations in R with (arbitrarily) high accuracy, though typically with substantial speed penalty. This is particularly important and useful for checking and exploring the numerical stability and appropriateness of mathematical formulae that are translated to a computer language like \R, often without very careful consideration of the limits of computer arithmetic. \bibliography{Rmpfr,log1mexp} FIXME: \textbf{Index} of all functions mentioned \dots \end{document}