Created
July 2, 2025 00:30
-
-
Save jonocarroll/8981f3198b282b14d1622dfb23c2afe4 to your computer and use it in GitHub Desktop.
ndigits floor(log10(abs(x))) + 1 benchmarks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## R - just vectorised (JIT) ################################################### | |
nd_R <- function(x) { | |
floor(log10(abs(x))) + 1 | |
} | |
nd_R(c(123456, 234, -72)) | |
#> [1] 6 3 2 | |
## Fortran - {quickr} (compiled) ############################################### | |
nd2f <- function(x) { | |
declare( | |
type(x = double(NA)) | |
) | |
floor(log10(abs(x))) + 1 | |
} | |
nd_F <- quickr::quick(nd2f) | |
nd_F(c(123456, 234, -72)) | |
#> [1] 6 3 2 | |
## C - {callme} (compiled) ##################################################### | |
callme::compile( | |
" | |
#include <R.h> | |
#include <Rinternals.h> | |
#include <math.h> | |
SEXP nd_C(SEXP x) { | |
int n = length(x); | |
SEXP result = PROTECT(allocVector(REALSXP, n)); | |
double *x_ptr = REAL(x); | |
double *result_ptr = REAL(result); | |
for (int i = 0; i < n; i++) { | |
result_ptr[i] = floor(log10(fabs(x_ptr[i]))) + 1.0; | |
} | |
UNPROTECT(1); | |
return result; | |
} | |
" | |
) | |
nd_C(c(123456, 234, -72)) | |
#> [1] 6 3 2 | |
## C++ - {Rcpp} (compiled) ##################################################### | |
nd_Rcpp <- Rcpp::cppFunction( | |
" | |
NumericVector floor_log10_plus1(NumericVector x) { | |
int n = x.size(); | |
NumericVector result(n); | |
for (int i = 0; i < n; i++) { | |
result[i] = std::floor(std::log10(std::abs(x[i]))) + 1; | |
} | |
return result; | |
} | |
" | |
) | |
nd_Rcpp(c(123456, 234, -72)) | |
#> [1] 6 3 2 | |
## Rust - {rextendr} (compiled) ################################################ | |
rextendr::rust_function( | |
r"( | |
fn nd_Rust(x: &[f64]) -> Vec<f64> { | |
x.iter() | |
.map(|&val| (val.abs().log10().floor() + 1.0)) | |
.collect() | |
})", | |
profile = "release" | |
) | |
#> ℹ build directory: '/private/var/folders/1h/k6c5hb4d2qx07m8kfqb54f9c0000gn/T/RtmpB7CYBi/file161661a57c637' | |
#> ✔ Writing '/private/var/folders/1h/k6c5hb4d2qx07m8kfqb54f9c0000gn/T/RtmpB7CYBi/file161661a57c637/target/extendr_wrappers.R' | |
nd_Rust(c(123456, 234, -72)) | |
#> [1] 6 3 2 | |
## Lua - {luajr} (JIT) ######################################################### | |
lua_f <- "function(x) | |
local result = {} | |
for i = 1, #x do | |
result[i] = math.floor(math.log10(math.abs(x[i]))) + 1 | |
end | |
return result | |
end" | |
nd_lua <- luajr::lua_func(lua_f, "r") | |
unlist(nd_lua(c(123456, 234, -72))) | |
#> [1] 6 3 2 | |
## Python - {reticulate} (interactive) ######################################### | |
library(reticulate) | |
reticulate::py_run_string( | |
' | |
import math | |
def nd_python(x): | |
return [math.floor(math.log10(abs(val))) + 1 for val in x] | |
' | |
) | |
py$nd_python(c(123456, 234, -72)) | |
#> [1] 6 3 2 | |
## BENCHMARKS ################################################################## | |
set.seed(1) | |
nums <- round(runif(1e4, -1, 1) * 1e4) | |
nums <- nums[nums != 0] | |
JuliaCall::julia_setup(file.path(path.expand("~"), ".juliaup/bin/")) | |
#> Julia version 1.11.1 at location /Users/jono/.julia/juliaup/julia-1.11.1+0.aarch64.apple.darwin14/bin will be used. | |
#> Loading setup script for JuliaCall... | |
#> Finish loading setup script for JuliaCall. | |
JuliaCall::julia_assign("nums", as.integer(nums)) | |
b <- bench::mark( | |
Python = py$nd_python(nums), | |
Lua = unlist(nd_lua(nums)), | |
Rust = nd_Rust(nums), | |
Julia = JuliaCall::julia_eval("ndigits.(nums)"), | |
`C++` = nd_Rcpp(nums), | |
C = nd_C(nums), | |
R = nd_R(nums), | |
Fortran = nd_F(nums), | |
min_iterations = 10, | |
check = TRUE | |
) | |
dplyr::arrange(b[, 1:8], median) | |
#> # A tibble: 8 × 6 | |
#> expression min median `itr/sec` mem_alloc `gc/sec` | |
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> | |
#> 1 C 21.4µs 23.8µs 41277. 78.2KB 95.2 | |
#> 2 Fortran 23.6µs 26.2µs 37384. 82.3KB 89.9 | |
#> 3 Rust 23µs 27.1µs 35273. 99.4KB 81.3 | |
#> 4 C++ 25.3µs 27.6µs 35378. 83.3KB 85.1 | |
#> 5 R 43.1µs 48µs 20681. 174.9KB 96.0 | |
#> 6 Julia 99.6µs 107.1µs 8940. 39.1KB 10.3 | |
#> 7 Python 405.9µs 439.4µs 2095. 39.1KB 2.01 | |
#> 8 Lua 14.5ms 14.8ms 67.5 156.3KB 0 | |
plot(b) | |
<!-- --> | |
Author
jonocarroll
commented
Jul 2, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment