I must be missing something with my understanding of precision here, but I thought that R could represent numbers along a grid with step size .Machine$double.eps
, but this appears not to be the case; in fact:
90 - .Machine$double.eps == 90
# [1] TRUE
This is strange to me because these two numbers (1) can be represented and (2) are non-zero:
sprintf('%.16a', c(90, .Machine$double.eps))
# [1] "0x1.6800000000000000p+6" "0x1.0000000000000000p-52"
The first place where the difference is numerically non-zero is even more suggestive:
90 - 32*.Machine$double.eps < 90
# [1] FALSE
90 - 33*.Machine$double.eps < 90
# [1] TRUE
This kind of result points straight to precision issues but there's some gap in my understanding here...
If 90 - .Machine$double.eps == 90
, why isn't double.eps
larger on my machine?
The results here suggest to me that actually I should have .Machine$double.eps == 2^5 * .Machine$double.eps
...
The effect is known as loss of significance (https://en.wikipedia.org/wiki/Loss_of_significance).
The significant digits of 90 shift the .Machine$double.eps
away. Try
(90 - 46*.Machine$double.eps) == 90
this should give you FALSE
.
Definition of a machine.eps: it is the lowest value eps
for which 1+eps
is not 1
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.
x <- 3.8
(x + 2*.Machine$double.eps) == x
x <- 4
(x + 2*.Machine$double.eps) == x
# ...
x <- 63
(x + 32*.Machine$double.eps) == x
x <- 64
(x + 32*.Machine$double.eps) == x
The absolute precision of the floating point representation varies with x
, but the relative precision is nearly constant over the range of the floating point numbers.