Skip to content

Instantly share code, notes, and snippets.

@knapply
Last active January 31, 2021 18:43
Show Gist options
  • Save knapply/38e1e3e718444b1733fa47cf61561dba to your computer and use it in GitHub Desktop.
Save knapply/38e1e3e718444b1733fa47cf61561dba to your computer and use it in GitHub Desktop.
// [[Rcpp::plugins(cpp17)]]
#include <Rcpp.h>
#include <fast_float/fast_float.h>
// [[Rcpp::depends(RcppFastFloat)]]
// [[Rcpp::export]]
SEXP fastfloat_s(Rcpp::CharacterVector invec) {
const auto n = invec.size();
Rcpp::DoubleVector out(n, NA_REAL);
double d;
for (R_xlen_t i = 0; i < n; ++i) {
std::string s(invec[i]);
auto res = fast_float::from_chars(s.data(), s.data() + s.size(), d);
if (res.ec == std::errc()) {
out[i] = d;
}
}
return out;
}
// [[Rcpp::export]]
SEXP fastfloat_sv(Rcpp::CharacterVector invec) {
const auto n = invec.size();
Rcpp::DoubleVector out(n, NA_REAL);
double d;
for (R_xlen_t i = 0; i < n; ++i) {
std::string_view s(invec[i]);
auto res = fast_float::from_chars(s.cbegin(), s.cend(), d);
if (res.ec == std::errc()) {
out[i] = d;
}
}
return out;
}
#ifdef __cpp_lib_string_view
#include <string_view>
#endif
// [[Rcpp::export(as.double2)]]
SEXP fastfloat2(const Rcpp::CharacterVector invec) {
const auto n = invec.size();
Rcpp::DoubleVector out(n, NA_REAL);
double d;
bool any_failures = false;
for (R_xlen_t i = 0; i < n; ++i) {
#ifdef __cpp_lib_string_view
std::string_view s(invec[i]);
auto res = fast_float::from_chars(s.cbegin(), s.cend(), d);
#else
std::string s(invec[i]);
auto res = fast_float::from_chars(s.data(), s.data() + s.size(), d);
#endif
if (res.ec == std::errc()) {
out[i] = d;
} else {
any_failures = true;
}
}
if (any_failures) {
Rcpp::warning("NAs introduced by coercion");
}
return out;
}
/*** R
N <- 1e6
set.seed(42)
invec <- sample(sqrt(seq(1:N)))
input <- sample(
c(rep(c("junk1", "junk2", "more junk!"), N, replace=T), as.character(invec))
)
suppressWarnings(
microbenchmark::microbenchmark(
as.double(input),
fastfloat_s(input),
fastfloat_sv(input),
as.double2(input), # same as fastfloat_sv, w/ warn on failures
check = "equal"
)
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> as.double(input) 779.2677 794.8253 815.7074 805.1494 836.4509 954.8745 100
#> fastfloat_s(input) 201.6056 208.4925 229.3757 212.7901 245.5257 544.1641 100
#> fastfloat_sv(input) 161.9853 168.6134 183.3555 171.3232 201.8738 487.4326 100
#> as.double2(input) 161.8312 167.4808 186.2112 171.3153 201.8792 522.9541 100
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment