Is there a "best practice" for less-than-equal comparisons with floating point number after a series of floating-point arithmetic operations?
I have the following example in R (although the question applies to any language using floating-point). I have a double x = 1
on which I apply a series of additions and subtractions. In the end x
should be exactly one but is not due to floating-point arithmetic (from what I gather). Here is the example:
> stop_times <- seq(0.25, 2, by = .25)
> expr <- expression(replicate(100,{
x <- 1
for(i in 1:10) {
tmp <- rexp(1, 1)
n <- sample.int(1e2, 1)
delta <- tmp / n
for(j in 1:n)
x <- x - delta
x <- x + tmp
}
# "correct" answer is 4
which.max(x <= stop_times)
}))
> eval(expr)
[1] 5 5 5 4 4 4 5 5 5 4 5 4 4 4 5 5 4 4 5 4 5 4 5 4 5 5 5 4 4 4 4 4 4 4 4 4 5 5 5 5 5 4 5 4 5 5 5 4 4 5 5 5 4 4 5 5 5 4 4 4 4 4 4
[64] 5 4 4 4 5 5 5 4 4 4 5 4 4 4 4 4 4 4 4 5 5 5 5 4 4 4 5 5 5 5 5 4 4 4 5 5 4
A (naive?) solution is to add some arbitrary small positive number to the right hand side of the inequality as follows
some_arbitrary_factor <- 100
stop_times <- seq(0.25, 2, by = .25) +
some_arbitrary_factor * .Machine$double.eps
eval(expr)
[1] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
[64] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
Is this "best practice" and if so are there guidelines on how to chose some_arbitrary_factor
?
My concrete problem is that I have time periods (t_0, t_1], (t_1, t_2], ...
and need to find out in which period a given observation x
is in. x
may have been set to one the boundaries t_i
after having undergone a series of floating-point arithmetic operations which should result in t_i
if exact operation where performed.
all.equal
as a built in way to test approximate equality. So you could use maybe something like(x<y) | all.equal(x,y)
– Auctioneerall.equal
function. The default is to Numerical comparisons for scale = NULL (the default) are typically on relative difference scale unless the target values are close to zero: First, the mean absolute difference of the two numerical vectors is computed. If this is smaller than tolerance or not finite, absolute differences are used, otherwise relative differences scaled by the mean absolute target value. wheretolerance
defaults tosqrt(.Machine$double.eps)
. I am not sure whether or not this is a common practice? – Trawl