From 6b4e9068b9081ca1012cf3a9ca9687f32ae8ff86 Mon Sep 17 00:00:00 2001 From: Nick Christofides <118103879+NicChr@users.noreply.github.com> Date: Wed, 10 Apr 2024 12:26:25 +0100 Subject: [PATCH] New 'set' math operations. --- CRAN-SUBMISSION | 3 - NAMESPACE | 9 ++ NEWS.md | 2 + R/cpp11.R | 36 +++++ R/set_math.R | 63 ++++++++ man/set_math.Rd | 66 ++++++++ src/cpp11.cpp | 72 +++++++++ src/set_math.cpp | 278 +++++++++++++++++++++++++++++++++ tests/testthat/test-set_math.R | 130 +++++++++++++++ 9 files changed, 656 insertions(+), 3 deletions(-) delete mode 100644 CRAN-SUBMISSION create mode 100644 R/set_math.R create mode 100644 man/set_math.Rd create mode 100644 src/set_math.cpp create mode 100644 tests/testthat/test-set_math.R diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION deleted file mode 100644 index 15269fd..0000000 --- a/CRAN-SUBMISSION +++ /dev/null @@ -1,3 +0,0 @@ -Version: 0.5.0 -Date: 2024-04-05 12:18:23 UTC -SHA: c48acb4a3b5fb5adabd316a191bcb8ae319f2732 diff --git a/NAMESPACE b/NAMESPACE index 85bdac1..bfb553d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -57,6 +57,15 @@ export(seq_) export(seq_id) export(seq_size) export(sequence_) +export(set_abs) +export(set_ceiling) +export(set_change_sign) +export(set_exp) +export(set_floor) +export(set_log) +export(set_round) +export(set_sqrt) +export(set_trunc) export(setdiff_) export(sset) export(unlisted_length) diff --git a/NEWS.md b/NEWS.md index 0d82552..e2f68f6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # cheapr (Development version) +* New maths functions that transform data by reference. + * Fixed an inconsistency of when `sequence_()` would error when supplied with a zero-length size argument. diff --git a/R/cpp11.R b/R/cpp11.R index db0a3a9..27cd641 100644 --- a/R/cpp11.R +++ b/R/cpp11.R @@ -128,6 +128,42 @@ cpp_sequence_id <- function(size) { .Call(`_cheapr_cpp_sequence_id`, size) } +cpp_set_abs <- function(x) { + .Call(`_cheapr_cpp_set_abs`, x) +} + +cpp_set_floor <- function(x) { + .Call(`_cheapr_cpp_set_floor`, x) +} + +cpp_set_ceiling <- function(x) { + .Call(`_cheapr_cpp_set_ceiling`, x) +} + +cpp_set_trunc <- function(x) { + .Call(`_cheapr_cpp_set_trunc`, x) +} + +cpp_set_round <- function(x, digits) { + .Call(`_cheapr_cpp_set_round`, x, digits) +} + +cpp_set_change_sign <- function(x) { + .Call(`_cheapr_cpp_set_change_sign`, x) +} + +cpp_set_exp <- function(x) { + .Call(`_cheapr_cpp_set_exp`, x) +} + +cpp_set_sqrt <- function(x) { + .Call(`_cheapr_cpp_set_sqrt`, x) +} + +cpp_set_log <- function(x, base) { + .Call(`_cheapr_cpp_set_log`, x, base) +} + is_alt_compact_seq <- function(x) { .Call(`_cheapr_is_alt_compact_seq`, x) } diff --git a/R/set_math.R b/R/set_math.R new file mode 100644 index 0000000..772f2b9 --- /dev/null +++ b/R/set_math.R @@ -0,0 +1,63 @@ +#' Math operations by reference +#' +#' @description +#' These functions transform your variable by reference, with no copies being made. +#' +#' @param x A numeric vector. +#' @param digits Number of digits to round to. +#' @param base Logarithm base. +#' +#' @details +#' These functions are particularly useful for situations +#' where you have made a copy and then +#' wish to perform further operations without creating more copies. \cr +#' `NA` and `NaN` values are ignored and never updated. \cr +#' These functions will \bold{not work} on \bold{any} classed objects, meaning they +#' only work on standard integer and numeric vectors and matrices. +#' +#' @returns +#' The exact same object with no copy made, just transformed. +#' +#' @examples +#' library(cheapr) +#' library(bench) +#' +#' x <- rnorm(2e05) +#' options(cheapr.cores = 2) +#' mark( +#' base = exp(log(abs(x))), +#' cheapr = set_exp(set_log(set_abs(x))) +#' ) +#' options(cheapr.cores = 1) +#' +#' @rdname set_math +#' @export +set_abs <- cpp_set_abs +#' @rdname set_math +#' @export +set_floor <- cpp_set_floor +#' @rdname set_math +#' @export +set_ceiling <- cpp_set_ceiling +#' @rdname set_math +#' @export +set_trunc <- cpp_set_trunc +#' @rdname set_math +#' @export +set_exp <- cpp_set_exp +#' @rdname set_math +#' @export +set_sqrt <- cpp_set_sqrt +#' @rdname set_math +#' @export +set_change_sign <- cpp_set_change_sign +#' @rdname set_math +#' @export +set_round <- function(x, digits = 0){ + cpp_set_round(x, digits) +} +#' @rdname set_math +#' @export +set_log <- function(x, base = exp(1)){ + cpp_set_log(x, base) +} diff --git a/man/set_math.Rd b/man/set_math.Rd new file mode 100644 index 0000000..2423bf4 --- /dev/null +++ b/man/set_math.Rd @@ -0,0 +1,66 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/set_math.R +\name{set_abs} +\alias{set_abs} +\alias{set_floor} +\alias{set_ceiling} +\alias{set_trunc} +\alias{set_exp} +\alias{set_sqrt} +\alias{set_change_sign} +\alias{set_round} +\alias{set_log} +\title{Math operations by reference} +\usage{ +set_abs(x) + +set_floor(x) + +set_ceiling(x) + +set_trunc(x) + +set_exp(x) + +set_sqrt(x) + +set_change_sign(x) + +set_round(x, digits = 0) + +set_log(x, base = exp(1)) +} +\arguments{ +\item{x}{A numeric vector.} + +\item{digits}{Number of digits to round to.} + +\item{base}{Logarithm base.} +} +\value{ +The exact same object with no copy made, just transformed. +} +\description{ +These functions transform your variable by reference, with no copies being made. +} +\details{ +These functions are particularly useful for situations +where you have made a copy and then +wish to perform further operations without creating more copies. \cr +\code{NA} and \code{NaN} values are ignored and never updated. \cr +These functions will \bold{not work} on \bold{any} classed objects, meaning they +only work on standard integer and numeric vectors and matrices. +} +\examples{ +library(cheapr) +library(bench) + +x <- rnorm(2e05) +options(cheapr.cores = 2) +mark( + base = exp(log(abs(x))), + cheapr = set_exp(set_log(set_abs(x))) +) +options(cheapr.cores = 1) + +} diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 09f4d06..c8da724 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -229,6 +229,69 @@ extern "C" SEXP _cheapr_cpp_sequence_id(SEXP size) { return cpp11::as_sexp(cpp_sequence_id(cpp11::as_cpp>(size))); END_CPP11 } +// set_math.cpp +SEXP cpp_set_abs(SEXP x); +extern "C" SEXP _cheapr_cpp_set_abs(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_abs(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_floor(SEXP x); +extern "C" SEXP _cheapr_cpp_set_floor(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_floor(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_ceiling(SEXP x); +extern "C" SEXP _cheapr_cpp_set_ceiling(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_ceiling(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_trunc(SEXP x); +extern "C" SEXP _cheapr_cpp_set_trunc(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_trunc(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_round(SEXP x, int digits); +extern "C" SEXP _cheapr_cpp_set_round(SEXP x, SEXP digits) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_round(cpp11::as_cpp>(x), cpp11::as_cpp>(digits))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_change_sign(SEXP x); +extern "C" SEXP _cheapr_cpp_set_change_sign(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_change_sign(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_exp(SEXP x); +extern "C" SEXP _cheapr_cpp_set_exp(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_exp(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_sqrt(SEXP x); +extern "C" SEXP _cheapr_cpp_set_sqrt(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_sqrt(cpp11::as_cpp>(x))); + END_CPP11 +} +// set_math.cpp +SEXP cpp_set_log(SEXP x, double base); +extern "C" SEXP _cheapr_cpp_set_log(SEXP x, SEXP base) { + BEGIN_CPP11 + return cpp11::as_sexp(cpp_set_log(cpp11::as_cpp>(x), cpp11::as_cpp>(base))); + END_CPP11 +} // sset.cpp bool is_alt_compact_seq(SEXP x); extern "C" SEXP _cheapr_is_alt_compact_seq(SEXP x) { @@ -347,10 +410,19 @@ static const R_CallMethodDef CallEntries[] = { {"_cheapr_cpp_row_na_counts", (DL_FUNC) &_cheapr_cpp_row_na_counts, 1}, {"_cheapr_cpp_sequence", (DL_FUNC) &_cheapr_cpp_sequence, 3}, {"_cheapr_cpp_sequence_id", (DL_FUNC) &_cheapr_cpp_sequence_id, 1}, + {"_cheapr_cpp_set_abs", (DL_FUNC) &_cheapr_cpp_set_abs, 1}, {"_cheapr_cpp_set_add_attr", (DL_FUNC) &_cheapr_cpp_set_add_attr, 3}, {"_cheapr_cpp_set_add_attributes", (DL_FUNC) &_cheapr_cpp_set_add_attributes, 3}, + {"_cheapr_cpp_set_ceiling", (DL_FUNC) &_cheapr_cpp_set_ceiling, 1}, + {"_cheapr_cpp_set_change_sign", (DL_FUNC) &_cheapr_cpp_set_change_sign, 1}, + {"_cheapr_cpp_set_exp", (DL_FUNC) &_cheapr_cpp_set_exp, 1}, + {"_cheapr_cpp_set_floor", (DL_FUNC) &_cheapr_cpp_set_floor, 1}, + {"_cheapr_cpp_set_log", (DL_FUNC) &_cheapr_cpp_set_log, 2}, {"_cheapr_cpp_set_rm_attr", (DL_FUNC) &_cheapr_cpp_set_rm_attr, 2}, {"_cheapr_cpp_set_rm_attributes", (DL_FUNC) &_cheapr_cpp_set_rm_attributes, 1}, + {"_cheapr_cpp_set_round", (DL_FUNC) &_cheapr_cpp_set_round, 2}, + {"_cheapr_cpp_set_sqrt", (DL_FUNC) &_cheapr_cpp_set_sqrt, 1}, + {"_cheapr_cpp_set_trunc", (DL_FUNC) &_cheapr_cpp_set_trunc, 1}, {"_cheapr_cpp_sset_df", (DL_FUNC) &_cheapr_cpp_sset_df, 2}, {"_cheapr_cpp_sset_range", (DL_FUNC) &_cheapr_cpp_sset_range, 4}, {"_cheapr_cpp_vec_length", (DL_FUNC) &_cheapr_cpp_vec_length, 1}, diff --git a/src/set_math.cpp b/src/set_math.cpp new file mode 100644 index 0000000..ab21a9d --- /dev/null +++ b/src/set_math.cpp @@ -0,0 +1,278 @@ +#include "cheapr_cpp.h" +#include +#include + +// Basic math operations by reference +// All NA and NaN values are ignored + +void cpp_check_numeric(SEXP x){ + if (!(Rf_isNumeric(x) && !Rf_isObject(x))){ + Rf_error("x must be a numeric vector"); + } +} + +[[cpp11::register]] +SEXP cpp_set_abs(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + switch (TYPEOF(x)){ + case INTSXP: { + int *p_x = INTEGER(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] != NA_INTEGER) p_x[i] = std::abs(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] != NA_INTEGER) p_x[i] = std::abs(p_x[i]); + } + } + break; + } + case REALSXP: { + double *p_x = REAL(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::fabs(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::fabs(p_x[i]); + } + } + break; + } + } + return x; +} + +[[cpp11::register]] +SEXP cpp_set_floor(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + if (Rf_isReal(x)){ + double *p_x = REAL(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::floor(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::floor(p_x[i]); + } + } + } + return x; +} + +[[cpp11::register]] +SEXP cpp_set_ceiling(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + if (Rf_isReal(x)){ + double *p_x = REAL(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::ceil(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::ceil(p_x[i]); + } + } + } + return x; +} + +[[cpp11::register]] +SEXP cpp_set_trunc(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + if (Rf_isReal(x)){ + double *p_x = REAL(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::trunc(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::trunc(p_x[i]); + } + } + } + return x; +} + +[[cpp11::register]] +SEXP cpp_set_round(SEXP x, int digits){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + if (Rf_isReal(x)){ + double *p_x = REAL(x); + if (n_cores > 1){ + int n_cores = num_cores(); + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]){ + double temp = p_x[i]; + temp *= std::pow(10, digits); + temp = std::round(temp); + temp *= std::pow(10, -(digits)); + p_x[i] = temp; + } + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]){ + double temp = p_x[i]; + temp *= std::pow(10, digits); + temp = std::round(temp); + // temp -= std::remainder(temp, 1.0); + temp *= std::pow(10, -(digits)); + // temp = std::nearbyint( temp * 0.5 ) * 2.0 * std::pow(10, -digits); + p_x[i] = temp; + } + } + } + } + return x; +} + +[[cpp11::register]] +SEXP cpp_set_change_sign(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + switch (TYPEOF(x)){ + case INTSXP: { + int *p_x = INTEGER(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] != NA_INTEGER) p_x[i] = -p_x[i]; + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] != NA_INTEGER) p_x[i] = -p_x[i]; + } + } + break; + } + case REALSXP: { + double *p_x = REAL(x); + if (n_cores > 1){ + int n_cores = num_cores(); + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = -p_x[i]; + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = -p_x[i]; + } + } + break; + } + } + return x; +} + +[[cpp11::register]] +SEXP cpp_set_exp(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + Rf_protect(x = Rf_coerceVector(x, REALSXP)); + double *p_x = REAL(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::exp(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::exp(p_x[i]); + } + } + Rf_unprotect(1); + return x; +} + +[[cpp11::register]] +SEXP cpp_set_sqrt(SEXP x){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + Rf_protect(x = Rf_coerceVector(x, REALSXP)); + double *p_x = REAL(x); + if (n_cores > 1){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::sqrt(p_x[i]); + } + } else { + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::sqrt(p_x[i]); + } + } + Rf_unprotect(1); + return x; +} + +[[cpp11::register]] +SEXP cpp_set_log(SEXP x, double base){ + cpp_check_numeric(x); + R_xlen_t n = Rf_xlength(x); + int n_cores = n >= 100000 ? num_cores() : 1; + Rf_protect(x = Rf_coerceVector(x, REALSXP)); + double *p_x = REAL(x); + if (n_cores > 1){ + if (base == std::exp(1)){ + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::log(p_x[i]); + } + } else { + double log_base = std::log(base); + OMP_PARALLEL_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = (std::log(p_x[i]) / log_base); + } + } + } else { + if (base == std::exp(1)){ + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = std::log(p_x[i]); + } + } else { + double log_base = std::log(base); + OMP_FOR_SIMD + for (R_xlen_t i = 0; i < n; ++i) { + if (p_x[i] == p_x[i]) p_x[i] = (std::log(p_x[i]) / log_base); + } + } + } + Rf_unprotect(1); + return x; +} diff --git a/tests/testthat/test-set_math.R b/tests/testthat/test-set_math.R new file mode 100644 index 0000000..8022ce1 --- /dev/null +++ b/tests/testthat/test-set_math.R @@ -0,0 +1,130 @@ +test_that("math operations", { + options(cheapr.cores = 2) + + # The first 2 will not trigger multi-threaded calculations + make_test_data1 <- function(){ + set.seed(3742) + assign("x", fill_with_na(rnorm(10^3), 50), + envir = parent.frame()) + } + make_test_data2 <- function(){ + set.seed(3742) + assign("x", fill_with_na(sample.int(100, 10^3, TRUE), 50), + envir = parent.frame()) + } + make_test_data3 <- function(){ + set.seed(3742) + assign("x", fill_with_na(rnorm(10^5), 10^3), + envir = parent.frame()) + } + make_test_data4 <- function(){ + set.seed(3742) + assign("x", fill_with_na(sample.int(100, 10^5, TRUE), 10^3), + envir = parent.frame()) + } + + expect_error(set_abs(iris)) + expect_error(set_floor(iris)) + expect_error(set_ceiling(iris)) + expect_error(set_trunc(iris)) + expect_error(set_log(iris)) + expect_error(set_exp(iris)) + expect_error(set_sqrt(iris)) + expect_error(set_round(iris)) + + make_test_data1() + expect_equal( + round(x, 2), + set_round(x, 2) + ) + make_test_data1() + expect_equal( + round(x), + set_round(x) + ) + make_test_data1() + expect_equal(round(x, 1),set_round(x, 1)) + make_test_data1() + expect_equal(abs(x), set_abs(x)) + make_test_data1() + expect_identical(floor(x), set_floor(x)) + make_test_data1() + expect_identical(ceiling(x), set_ceiling(x)) + make_test_data1() + expect_identical(trunc(x), set_trunc(x)) + make_test_data1() + expect_equal(exp(x), set_exp(x)) + make_test_data1() + expect_equal(log(abs(x)), set_log(set_abs(x))) + make_test_data1() + expect_equal(log10(abs(x)), set_log(set_abs(x), base = 10)) + make_test_data1() + expect_equal(sqrt(abs(x)), set_sqrt(set_abs(x))) + make_test_data1() + expect_equal(-x, set_change_sign(x)) + + + make_test_data2() + expect_equal(round(x, 1),set_round(x, 1)) + make_test_data2() + expect_equal(abs(x), set_abs(x)) + make_test_data2() + expect_equal(floor(x), set_floor(x)) + make_test_data2() + expect_equal(ceiling(x), set_ceiling(x)) + make_test_data2() + expect_equal(trunc(x), set_trunc(x)) + make_test_data2() + expect_equal(exp(x), set_exp(x)) + make_test_data2() + expect_equal(log(abs(x)), set_log(set_abs(x))) + make_test_data2() + expect_equal(log10(abs(x)), set_log(set_abs(x), base = 10)) + make_test_data2() + expect_equal(sqrt(abs(x)), set_sqrt(set_abs(x))) + make_test_data2() + expect_equal(-x, set_change_sign(x)) + + make_test_data3() + expect_equal(round(x, 1),set_round(x, 1)) + make_test_data3() + expect_equal(abs(x), set_abs(x)) + make_test_data3() + expect_equal(floor(x), set_floor(x)) + make_test_data3() + expect_equal(ceiling(x), set_ceiling(x)) + make_test_data3() + expect_equal(trunc(x), set_trunc(x)) + make_test_data3() + expect_equal(exp(x), set_exp(x)) + make_test_data3() + expect_equal(log(abs(x)), set_log(set_abs(x))) + make_test_data3() + expect_equal(log10(abs(x)), set_log(set_abs(x), base = 10)) + make_test_data3() + expect_equal(sqrt(abs(x)), set_sqrt(set_abs(x))) + make_test_data3() + expect_equal(-x, set_change_sign(x)) + + make_test_data4() + expect_equal(round(x, 1),set_round(x, 1)) + make_test_data4() + expect_equal(abs(x), set_abs(x)) + make_test_data4() + expect_equal(floor(x), set_floor(x)) + make_test_data4() + expect_equal(ceiling(x), set_ceiling(x)) + make_test_data4() + expect_equal(trunc(x), set_trunc(x)) + make_test_data4() + expect_equal(exp(x), set_exp(x)) + make_test_data4() + expect_equal(log(abs(x)), set_log(set_abs(x))) + make_test_data4() + expect_equal(log10(abs(x)), set_log(set_abs(x), base = 10)) + make_test_data4() + expect_equal(sqrt(abs(x)), set_sqrt(set_abs(x))) + make_test_data4() + expect_equal(-x, set_change_sign(x)) + options(cheapr.cores = 1) +})