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.equalas a built in way to test approximate equality. So you could use maybe something like(x<y) | all.equal(x,y)all.equalfunction. 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. wheretolerancedefaults tosqrt(.Machine$double.eps). I am not sure whether or not this is a common practice?