From b3c4eab086d0455efcb907b31fe82632478ee093 Mon Sep 17 00:00:00 2001 From: Nick Christofides <118103879+NicChr@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:04:40 +0000 Subject: [PATCH] Rewrote rel_diff in C++. --- DESCRIPTION | 2 +- R/cpp11.R | 4 ++++ R/diff.R | 2 +- src/cpp11.cpp | 8 ++++++++ src/cpp_doubles.cpp | 29 +++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index bf75746..8f9d958 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: cppdoubles Title: Fast Relative Comparisons of Floating Point Numbers in C++ -Version: 0.1.0 +Version: 0.1.0.9000 Authors@R: person("Nick", "Christofides", , "nick.christofides.r@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-9743-7342")) diff --git a/R/cpp11.R b/R/cpp11.R index fa41ecd..867a80d 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -19,3 +19,7 @@ cpp_double_lt_vectorised <- function(x, y, tolerance) { cpp_double_lte_vectorised <- function(x, y, tolerance) { .Call(`_cppdoubles_cpp_double_lte_vectorised`, x, y, tolerance) } + +cpp_rel_diff_vectorised <- function(x, y) { + .Call(`_cppdoubles_cpp_rel_diff_vectorised`, x, y) +} diff --git a/R/diff.R b/R/diff.R index 98ff5d9..2829305 100644 --- a/R/diff.R +++ b/R/diff.R @@ -13,7 +13,7 @@ #' @rdname diff #' @export rel_diff <- function(x, y){ - abs(x - y) / pmax(abs(x), abs(y)) + .Call(`_cppdoubles_cpp_rel_diff_vectorised`, x, y) } #' @rdname diff #' @export diff --git a/src/cpp11.cpp b/src/cpp11.cpp index be6f469..7f88300 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -40,6 +40,13 @@ extern "C" SEXP _cppdoubles_cpp_double_lte_vectorised(SEXP x, SEXP y, SEXP toler return cpp11::as_sexp(cpp_double_lte_vectorised(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(tolerance))); END_CPP11 } +// cpp_doubles.cpp +SEXP cpp_rel_diff_vectorised(SEXP x, SEXP y); +extern "C" SEXP _cppdoubles_cpp_rel_diff_vectorised(SEXP x, SEXP y) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_rel_diff_vectorised(cpp11::as_cpp>(x), cpp11::as_cpp>(y))); + END_CPP11 +} extern "C" { static const R_CallMethodDef CallEntries[] = { @@ -48,6 +55,7 @@ static const R_CallMethodDef CallEntries[] = { {"_cppdoubles_cpp_double_gte_vectorised", (DL_FUNC) &_cppdoubles_cpp_double_gte_vectorised, 3}, {"_cppdoubles_cpp_double_lt_vectorised", (DL_FUNC) &_cppdoubles_cpp_double_lt_vectorised, 3}, {"_cppdoubles_cpp_double_lte_vectorised", (DL_FUNC) &_cppdoubles_cpp_double_lte_vectorised, 3}, + {"_cppdoubles_cpp_rel_diff_vectorised", (DL_FUNC) &_cppdoubles_cpp_rel_diff_vectorised, 2}, {NULL, NULL, 0} }; } diff --git a/src/cpp_doubles.cpp b/src/cpp_doubles.cpp index af02028..6dd5322 100644 --- a/src/cpp_doubles.cpp +++ b/src/cpp_doubles.cpp @@ -255,3 +255,32 @@ SEXP cpp_double_lte_vectorised(SEXP x, SEXP y, SEXP tolerance) { Rf_unprotect(1); return out; } + +[[cpp11::register]] +SEXP cpp_rel_diff_vectorised(SEXP x, SEXP y) { + // double tolerance = std::sqrt(std::numeric_limits::epsilon()); + R_xlen_t x_len = Rf_xlength(x); + R_xlen_t y_len = Rf_xlength(y); + R_xlen_t n = std::max(x_len, y_len); + if (x_len <= 0 || y_len <= 0){ + // Avoid loop if any are length zero vectors + n = 0; + } + double *p_x = REAL(x); + double *p_y = REAL(y); + SEXP out = Rf_protect(Rf_allocVector(REALSXP, n)); + double *p_out = REAL(out); + R_xlen_t xi; + R_xlen_t yi; + for (R_xlen_t i = 0; i < n; ++i) { + xi = i % x_len; + yi = i % y_len; + p_out[i] = cpp_double_rel_diff(p_x[xi], p_y[yi]); + // If either is NA, out is NA + if ( cpp_double_is_na(p_x[xi]) || cpp_double_is_na(p_y[yi]) ){ + p_out[i] = NA_REAL; + } + } + Rf_unprotect(1); + return out; +}