I often end up in situations where it is necessary to check if the obtained difference is above machine precision. Seems like for this purpose R has a handy variable: .Machine$double.eps
. However when I turn to R source code for guidelines about using this value I see multiple different patterns.
Examples
Here are a few examples from stats
library:
t.test.R
if(stderr < 10 *.Machine$double.eps * abs(mx))
chisq.test.R
if(abs(sum(p)-1) > sqrt(.Machine$double.eps))
integrate.R
rel.tol < max(50*.Machine$double.eps, 0.5e-28)
lm.influence.R
e[abs(e) < 100 * .Machine$double.eps * median(abs(e))] <- 0
princomp.R
if (any(ev[neg] < - 9 * .Machine$double.eps * ev[1L]))
etc.
Questions
- How can one understand the reasoning behind all those different
10 *
,100 *
,50 *
andsqrt()
modifiers? - Are there guidelines about using
.Machine$double.eps
for adjusting differences due to precision issues?
The machine precision for
double
depends on its current value..Machine$double.eps
gives the precision when the values is 1. You can use the C functionnextAfter
to get the machine precision for other values.Adding value
a
to valueb
will not changeb
whena
is<=
half of it's machine precision. Checking if the difference is smaler than machine precision is done with<
. The modifiers might consider typical cases how often an addition did not show a change.In R the machine precision can be estimated with:
Each
double
value is representing a range. For a simple addition, the range of the result depends on the reange of each summand and also the range of their sum.For higher precission
Rmpfr
could be used.In case it could be converted to integer
gmp
could be used (what is in Rmpfr).Definition of a machine.eps: it is the lowest value
eps
for which1+eps
is not1
As a rule of thumb (assuming a floating point representation with base 2):
This
eps
makes the difference for the range 1 .. 2,for the range 2 .. 4 the precision is
2*eps
and so on.
Unfortunately, there is no good rule of thumb here. It's entirely determined by the needs of your program.
In R we have all.equal as a built in way to test approximate equality. So you could use maybe something like
(x<y) | all.equal(x,y
)Google mock has a number of floating point matchers for double precision comparisons, including
DoubleEq
andDoubleNear
. You can use them in an array matcher like this:Update:
Numerical Recipes provide a derivation to demonstrate that using a one-sided difference quotient,
sqrt
is a good choice of step-size for finite difference approximations of derivatives.The Wikipedia article site Numerical Recipes, 3rd edition, Section 5.7, which is pages 229-230 (a limited number of page views is available at http://www.nrbook.com/empanel/).
These IEEE floating point arithmetic is a well known limitation of computer arithmetic and is discussed in several places:
.
dplyr::near()
is another option for testing if two vectors of floating point numbers are equal.The function has a built in tolerance parameter:
tol = .Machine$double.eps^0.5
that can be adjusted. The default parameter is the same as the default forall.equal()
.