Hi all,
Could we modify the "%%" (modulo)-operator to include some tolerance for rounding-errors when supplied with doubles? It's not much work (patch supplied on the bottom), and I don't think it would break anything, only if you were really interested in analysing rounding differences. Any ideas about implementing this and overwriting base::`%%`, or would we want another method (as I've done for the moment)? Background I was writing some code where something has to happen at a certain interval, with progress indicated, something like this: interval <- .001 progress <- .1 for(i in 1:1000*interval) {myFun(i); Sys.sleep(interval); if(i %% progress, 0))) cat(i, '\n')} without interval and progress being known in advance. I could work around it and make i integer, or do something like isTRUE(all.equal(i %% progress,0)) || isTRUE(all.equal(i %% progress, progress), but I think my code is clearer as it is. And I like the idea behind all.equal: we want double to approximately identical. So my patch (with roxygen2-markup): #' Modulo-operator with near-equality #' #' The \code{\link[base:Arithmetic]{`\%\%`}} operator calculates the modulo, but sometimes has rounding errors, e.g. "\code{(9.1/.1) \%\% 1}" gives ~ 1, instead of 0.\cr #' Comparable to what all.equal does, this operator has some tolerance for small rounding errors.\cr #' If the answer would be equal to the divisor within a small tolerance, 0 is returned instead. #' #' For integer x and y, the normal \%\%-operator is used #' #' @usage `\%mod\%`(x, y, tolerance = sqrt(.Machine$double.eps)) #' x \%mod\% y #' @param x,y numeric vectors, similar to those passed on to \%\% #' @param tolerance numeric, maximum difference, see \code{\link[base]{all.equal}}. The default is ~ \code{1.5e-8} #' @return identical to the result for \%\%, unless the answer would be really close to y, in which case 0 is returned #' @note To specify tolerance, use the call \code{`\%mod\%`(x,y,tolerance)} #' @note The precedence for \code{\%mod\%} is the same as that for \code{\%\%} #' #' @name mod #' @rdname mod #' #' @export `%mod%` <- function(x,y, tolerance = sqrt(.Machine$double.eps)) { stopifnot(is.numeric(x), is.numeric(y), is.numeric(tolerance), !is.na(tolerance), length(tolerance)==1, tolerance>=0) if(is.integer(x) && is.integer(y)) { return(x %% y) } else { ans <- x %% y return(ifelse(abs(ans-y)<tolerance | abs(ans)<tolerance, 0, ans)) } } Best regards, Emil Bode [[alternative HTML version deleted]] ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel