Introducing 'insitu' - functions for in-place modification

insitu

Lifecycle: experimental

insitu provides some functions for modifying vectors in-situ (in place) without allocating a new vector.

This is an experimental package I wrote to try and figure out just how fast things could be in R.

Warning: Modifying vectors in-situ can be fast, but doing so violates some very strong norms within R internals.

Warning: Unless you are very confident on who has references to your data, do not use this package for in-place modification.

Modifying vectors in-place

Pros of modifying in-situ

  • Often faster as there is reduced memory allocation (and also reduced pressure on the garbage collector)
  • Often faster as there is no copying from the original vector into a new vector
  • By using C, we can override the copy-on-modify semantics usually used in R (regardless of how many references exist to the given object)

Cons of modifying in-situ

  • Normal R copy-on-modify behaviour is not followed - this will be a point of confusion as essentially everything in R uses copy-on-modify and not modification in-place.
  • Copying and allocating vectors is already very fast. It only takes a few microseconds to allocate memory for a vector of 1000 elements and assign new values into it. The speed saved by switching to in-situ modification will only possibly be useful if this operations is performed many, many times.

In the words of Luke Tierney in his User2020 keynote:

You should never modify something without duplicating it.

This package ignores this advice. Beware.

What’s in the box

insitu description integer real character
insitu_fill(x, value) Fill vector with the given value Yes Yes Yes
insitu_fill_runif(x, lower, upper) Fill vector with uniform random numbers Yes Yes
insitu_fill_runif_fast(x, lower, upper) Fill vector with uniform random numbers Yes Yes
insitu_replace(x, pos, values) Replace values in x with given values starting from the given position Yes Yes Yes
insitu_reverse(x) Reverse vector Yes Yes Yes
insitu_shuffle(x) Shuffle the elements of a vector Yes Yes Yes
insitu_shuffle_fast(x) Shuffle the elements of a vector Yes Yes Yes
insitu_sort(x) Sort the elements of a vector Yes Yes

Fast Variants

The _fast versions of some functions use their own random-number generator rather than the one supplied in R. This generator is lehmer64. It is very fast, but has different properties from R’s built in random number generator. Use with caution.

ALTREP utils

  • is_altrep(x) tests whether an object is an ALTREP
  • is_mutable(x) tests whether an object is mutable in-place by checking its reference count
  • get_refcnt(x) returns the reference count for the object

Installation

You can install from GitHub with:

# install.package('remotes')
remotes::install_github('coolbutuseless/insitu')

Future possibilities

  • In-place radix sort - instead of using qsort()
  • cummin, cummax etc
  • negate
  • diff

In-situ Replacement

insitu_replace() is analogous to replace() but replaces values in the current vector rather than creating a new one.

x <- integer(10)
insitu_replace(x, 6, 1:5)
x
 [1] 0 0 0 0 0 1 2 3 4 5

Click to show/hide benchmark code & results

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Assign values into a vector
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
N = c(1e1, 1e2, 1e3, 1e4, 1e5, 1e6)

res_rel <- bench::press(
  N = N,
  {
    x <- numeric(N)
    x[1] <- x[1]
    idx <- seq(1, N/2)
    ins <- as.numeric(idx)
    
    bench::mark(
      replace(x, idx, ins),
      insitu_replace(x, 1, ins),
      check    = TRUE,
      relative = TRUE
    )
  }
)

res_rel %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
replace(x, idx, ins) 1.160156 1.106230 1.000000 NaN
insitu_replace(x, 1, ins) 1.000000 1.000000 1.118310 NaN
replace(x, idx, ins) 1.797336 2.029647 1.000000 2.446429
insitu_replace(x, 1, ins) 1.000000 1.000000 2.281246 1.000000
replace(x, idx, ins) 5.195353 7.137832 1.000000 2.494071
insitu_replace(x, 1, ins) 1.000000 1.000000 6.741992 1.000000
replace(x, idx, ins) 15.738677 25.238643 1.000000 2.499401
insitu_replace(x, 1, ins) 1.000000 1.000000 24.600466 1.000000
replace(x, idx, ins) 19.240119 31.171246 1.000000 2.499940
insitu_replace(x, 1, ins) 1.000000 1.000000 27.534510 1.000000
replace(x, idx, ins) 19.387400 18.192379 1.000000 2.499994
insitu_replace(x, 1, ins) 1.000000 1.000000 17.034955 1.000000
res_abs <- bench::press(
  N = N,
  {
    x <- numeric(N)
    x[1] <- x[1]
    idx <- seq(1, N/2)
    ins <- as.numeric(idx)
    
    bench::mark(
      replace(x, idx, ins),
      insitu_replace(x, 1, ins),
      check    = TRUE,
      relative = FALSE
    )
  }
)

res_abs %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
replace(x, idx, ins) 1.15µs 1.33µs 604227.9275 0B
insitu_replace(x, 1, ins) 1.01µs 1.23µs 626725.4925 0B
replace(x, idx, ins) 1.92µs 2.62µs 320836.0319 1.07KB
insitu_replace(x, 1, ins) 1.05µs 1.26µs 681850.9878 448B
replace(x, idx, ins) 6.01µs 7.62µs 113786.9416 9.86KB
insitu_replace(x, 1, ins) 1.16µs 1.31µs 711556.3865 3.95KB
replace(x, idx, ins) 42.78µs 80.93µs 11838.8043 97.75KB
insitu_replace(x, 1, ins) 2.8µs 3.13µs 299449.9164 39.11KB
replace(x, idx, ins) 417.16µs 726.44µs 1459.5060 976.66KB
insitu_replace(x, 1, ins) 21.53µs 24.7µs 37556.2759 390.67KB
replace(x, idx, ins) 4.68ms 5.03ms 184.7498 9.54MB
insitu_replace(x, 1, ins) 245.95µs 287.6µs 2939.2212 3.81MB

In-situ fill

insitu_fill() is analogous to replace() but assigns the value into the current vector rather than creating a new one.

x <- integer(10)
insitu_fill(x, 3L)
x
 [1] 3 3 3 3 3 3 3 3 3 3

Click to show/hide benchmark code & results

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Assign values into a vector
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# N = c(1e1, 1e2, 1e3, 1e4, 1e5, 1e6)

res_rel <- bench::press(
  N = N,
  {
    x <- numeric(N)
    idx <- 1:N
    ins <- 99
    
    bench::mark(
      replace(x, idx, ins),
      insitu_fill(x, ins),
      check    = TRUE,
      relative = TRUE
    )
  }
)

res_rel %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
replace(x, idx, ins) 1.229236 1.298578 1.000000 NaN
insitu_fill(x, ins) 1.000000 1.000000 1.326658 NaN
replace(x, idx, ins) 1.363341 1.667515 1.000000 Inf
insitu_fill(x, ins) 1.000000 1.000000 1.830421 NaN
replace(x, idx, ins) 1.000000 1.181148 1.000000 Inf
insitu_fill(x, ins) 1.060364 1.000000 1.324551 NaN
replace(x, idx, ins) 1.000000 1.590073 1.000000 Inf
insitu_fill(x, ins) 1.347507 1.000000 1.572959 NaN
replace(x, idx, ins) 1.000000 1.455272 1.000000 Inf
insitu_fill(x, ins) 1.343936 1.000000 1.357076 NaN
replace(x, idx, ins) 1.000000 1.000000 1.013211 Inf
insitu_fill(x, ins) 1.217040 1.111741 1.000000 NaN
res_abs <- bench::press(
  N = N,
  {
    x <- numeric(N)
    idx <- 1:N
    ins <- 99
    
    bench::mark(
      replace(x, idx, ins),
      insitu_fill(x, ins),
      check    = TRUE,
      relative = FALSE
    )
  }
)

res_abs %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
replace(x, idx, ins) 1.15µs 1.35µs 662250.3834 0B
insitu_fill(x, ins) 867ns 1.05µs 850804.0257 0B
replace(x, idx, ins) 1.67µs 2.02µs 386154.9397 1.27KB
insitu_fill(x, ins) 1.26µs 1.36µs 597002.8780 0B
replace(x, idx, ins) 4.29µs 5.64µs 155360.2575 11.81KB
insitu_fill(x, ins) 4.72µs 4.92µs 194406.1723 0B
replace(x, idx, ins) 29.01µs 66.16µs 14534.3837 117.28KB
insitu_fill(x, ins) 38.24µs 41.7µs 22958.4854 0B
replace(x, idx, ins) 273.27µs 621.43µs 1624.1870 1.15MB
insitu_fill(x, ins) 380.05µs 420.89µs 2334.8499 0B
replace(x, idx, ins) 3.25ms 3.7ms 241.1781 11.44MB
insitu_fill(x, ins) 3.69ms 4.21ms 235.6181 0B

In-situ sort

insitu_sort() is analogous to sort() but sorts values in the current vector rather than creating a new one.

x <- sample(10)
insitu_sort(x)
x
 [1]  1  2  3  4  5  6  7  8  9 10

Click to show/hide benchmark code & results

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Assign values into a vector
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# N = c(1e1, 1e2, 1e3, 1e4, 1e5, 1e6)

res_rel <- bench::press(
  N = N,
  {
    x <- runif(N)

    bench::mark(
      sort(x),
      insitu_sort(x),
      check    = TRUE,
      relative = TRUE
    )
  }
)

res_rel %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
sort(x) 44.192865 42.981013 1.000000 NaN
insitu_sort(x) 1.000000 1.000000 40.303405 NaN
sort(x) 26.989432 28.228392 1.000000 Inf
insitu_sort(x) 1.000000 1.000000 29.388349 NaN
sort(x) 6.541023 7.107368 1.000000 Inf
insitu_sort(x) 1.000000 1.000000 7.478798 NaN
sort(x) 1.937674 2.525904 1.000000 Inf
insitu_sort(x) 1.000000 1.000000 2.521864 NaN
sort(x) 1.064732 1.699909 1.000000 Inf
insitu_sort(x) 1.000000 1.000000 1.669044 NaN
sort(x) 1.025600 1.175356 1.000000 Inf
insitu_sort(x) 1.000000 1.000000 1.330278 NaN
res_abs <- bench::press(
  N = N,
  {
    x <- runif(N)
    
    bench::mark(
      sort(x),
      insitu_sort(x),
      check    = TRUE,
      relative = FALSE
    )
  }
)

res_abs %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
sort(x) 40.45µs 47.63µs 19323.2410 0B
insitu_sort(x) 899ns 1.05µs 823655.6466 0B
sort(x) 41.66µs 49.55µs 17223.6604 1.27KB
insitu_sort(x) 1.51µs 1.73µs 530651.7167 0B
sort(x) 47.28µs 57.11µs 15012.7291 11.81KB
insitu_sort(x) 7.04µs 7.86µs 109586.8553 0B
sort(x) 107.95µs 173.51µs 5329.9525 117.28KB
insitu_sort(x) 62.18µs 65.97µs 14349.4585 0B
sort(x) 653.57µs 1.2ms 832.5820 1.15MB
insitu_sort(x) 591.85µs 674.37µs 1450.3867 0B
sort(x) 6.83ms 9.13ms 110.9861 11.44MB
insitu_sort(x) 6ms 6.54ms 151.5278 0B

In-situ Shuffle

insitu_shuffle() is analogous to sample() but shuffles values in the current vector rather than creating a new one.

x <- c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
insitu_shuffle(x)
x
 [1] 9 6 0 3 5 7 8 1 4 2

Click to show/hide benchmark code & results

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Assign values into a vector
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# N = c(1e1, 1e2, 1e3, 1e4, 1e5, 1e6)

res_rel <- bench::press(
  N = N,
  {
    x <- runif(N)

    bench::mark(
      sample(x),
      insitu_shuffle(x),
      insitu_shuffle_fast(x),
      check    = FALSE,
      relative = TRUE
    )
  }
)

res_rel %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
sample(x) 7.385214 7.171458 1.000000 Inf
insitu_shuffle(x) 1.000000 1.000000 7.053456 NaN
insitu_shuffle_fast(x) 2.315175 2.382957 2.972455 Inf
sample(x) 5.043932 6.137506 1.000000 Inf
insitu_shuffle(x) 1.000000 1.000000 5.700903 NaN
insitu_shuffle_fast(x) 1.163097 1.310498 4.336377 Inf
sample(x) 7.971023 7.385535 1.000000 Inf
insitu_shuffle(x) 2.233688 2.114623 3.455347 NaN
insitu_shuffle_fast(x) 1.000000 1.000000 7.182072 Inf
sample(x) 11.935903 13.344195 1.000000 Inf
insitu_shuffle(x) 3.137795 3.202304 4.109921 NaN
insitu_shuffle_fast(x) 1.000000 1.000000 12.875612 Inf
sample(x) 14.665743 15.785546 1.000000 Inf
insitu_shuffle(x) 3.228209 3.517930 4.345945 NaN
insitu_shuffle_fast(x) 1.000000 1.000000 15.129547 Inf
sample(x) 12.858372 12.382391 1.000000 Inf
insitu_shuffle(x) 2.860528 3.340090 3.774192 NaN
insitu_shuffle_fast(x) 1.000000 1.000000 10.934830 Inf
res_abs <- bench::press(
  N = N,
  {
    x <- runif(N)
    
    bench::mark(
      sample(x),
      insitu_shuffle(x),
      insitu_shuffle_fast(x),
      check    = FALSE,
      relative = FALSE
    )
  }
)

res_abs %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
sample(x) 5.89µs 7.16µs 129084.90804 2.49KB
insitu_shuffle(x) 818ns 975ns 952295.33521 0B
insitu_shuffle_fast(x) 1.77µs 2.26µs 414345.47824 2.49KB
sample(x) 9.3µs 11.41µs 83312.86336 4.2KB
insitu_shuffle(x) 1.74µs 2.01µs 446962.15223 0B
insitu_shuffle_fast(x) 2.03µs 2.58µs 364783.29064 2.49KB
sample(x) 41.86µs 46.39µs 20845.99544 18.27KB
insitu_shuffle(x) 11.91µs 13.28µs 71481.19180 0B
insitu_shuffle_fast(x) 5.28µs 6.12µs 150911.04998 2.49KB
sample(x) 419.28µs 500.08µs 1956.51662 158.89KB
insitu_shuffle(x) 112.27µs 120.26µs 7967.50222 0B
insitu_shuffle_fast(x) 35.59µs 38.02µs 24551.59483 2.49KB
sample(x) 5.54ms 6.69ms 143.55062 1.53MB
insitu_shuffle(x) 1.21ms 1.39ms 699.63921 0B
insitu_shuffle_fast(x) 375.44µs 391.24µs 2437.92941 2.49KB
sample(x) 81.23ms 83.06ms 11.88900 15.26MB
insitu_shuffle(x) 17.31ms 22.98ms 44.18255 0B
insitu_shuffle_fast(x) 6.15ms 7.09ms 132.75626 2.49KB

In-situ Reverse

insitu_reverse() is analogous to rev() but reverses values in the current vector rather than creating a new one.

x <- c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
insitu_reverse(x)
x
 [1] 9 8 7 6 5 4 3 2 1 0

Click to show/hide benchmark code & results

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Assign values into a vector
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# N = c(1e1, 1e2, 1e3, 1e4, 1e5, 1e6)

res_rel <- bench::press(
  N = N,
  {
    x <- runif(N)

    bench::mark(
      rev(x),
      insitu_reverse(x),
      check    = TRUE,
      relative = TRUE
    )
  }
)

res_rel %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
rev(x) 4.001531 4.259724 1.000000 NaN
insitu_reverse(x) 1.000000 1.000000 4.248889 NaN
rev(x) 4.519830 5.314951 1.000000 Inf
insitu_reverse(x) 1.000000 1.000000 5.458907 NaN
rev(x) 5.461066 6.297345 1.000000 Inf
insitu_reverse(x) 1.000000 1.000000 6.684822 NaN
rev(x) 6.170470 15.868918 1.000000 Inf
insitu_reverse(x) 1.000000 1.000000 15.590267 NaN
rev(x) 7.360748 17.015706 1.000000 Inf
insitu_reverse(x) 1.000000 1.000000 15.858245 NaN
rev(x) 6.505439 6.468984 1.000000 Inf
insitu_reverse(x) 1.000000 1.000000 6.249604 NaN
res_abs <- bench::press(
  N = N,
  {
    x <- runif(N)
    
    bench::mark(
      rev(x),
      insitu_reverse(x),
      check    = TRUE,
      relative = FALSE
    )
  }
)

res_abs %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
rev(x) 2.54µs 3.35µs 279979.0743 0B
insitu_reverse(x) 641ns 764ns 1148403.6022 0B
rev(x) 3.02µs 3.7µs 231492.5363 1.27KB
insitu_reverse(x) 718ns 820ns 1110216.6455 0B
rev(x) 5.33µs 7.75µs 113639.8907 11.81KB
insitu_reverse(x) 1.03µs 1.15µs 823221.0911 0B
rev(x) 34.01µs 79.71µs 11979.8707 117.28KB
insitu_reverse(x) 4.53µs 4.88µs 190598.4239 0B
rev(x) 278.97µs 716.12µs 1380.1388 1.15MB
insitu_reverse(x) 39.46µs 42.45µs 21911.3579 0B
rev(x) 2.87ms 3.5ms 252.3226 11.44MB
insitu_reverse(x) 425.69µs 525.97µs 1746.0251 0B

In-situ fill with random

insitu_fill_runif() is analogous to runif() but generates values in the current vector rather than creating a new one.

x <- integer(10)
insitu_fill_runif(x, 10, 15)
x
 [1] 14 10 10 14 15 13 11 10 10 11

Click to show/hide benchmark code & results

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Assign values into a vector
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# N = c(1e1, 1e2, 1e3, 1e4, 1e5, 1e6)

res_rel <- bench::press(
  N = N,
  {
    x <- numeric(N)

    bench::mark(
      runif(x),
      insitu_fill_runif(x, 0, 1),
      insitu_fill_runif_fast(x, 0, 1),
      check    = FALSE,
      relative = TRUE
    )
  }
)

res_rel %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
runif(x) 1.892204 1.952124 1.000000 Inf
insitu_fill_runif(x, 0, 1) 1.000000 1.000000 1.937939 NaN
insitu_fill_runif_fast(x, 0, 1) 1.870067 1.896525 1.054534 Inf
runif(x) 2.441160 2.689176 1.000000 Inf
insitu_fill_runif(x, 0, 1) 1.000000 1.000000 2.702906 NaN
insitu_fill_runif_fast(x, 0, 1) 1.209778 1.348808 2.093330 Inf
runif(x) 8.089969 7.102734 1.000000 Inf
insitu_fill_runif(x, 0, 1) 2.883208 2.530203 2.871414 NaN
insitu_fill_runif_fast(x, 0, 1) 1.000000 1.000000 6.659101 Inf
runif(x) 16.993506 19.090761 1.000000 Inf
insitu_fill_runif(x, 0, 1) 5.584250 5.586271 3.393810 NaN
insitu_fill_runif_fast(x, 0, 1) 1.000000 1.000000 18.507435 Inf
runif(x) 19.036940 22.376697 1.000000 Inf
insitu_fill_runif(x, 0, 1) 6.573531 6.956403 3.169354 NaN
insitu_fill_runif_fast(x, 0, 1) 1.000000 1.000000 21.028264 Inf
runif(x) 19.948139 20.726121 1.000000 Inf
insitu_fill_runif(x, 0, 1) 6.616963 6.674905 3.027731 NaN
insitu_fill_runif_fast(x, 0, 1) 1.000000 1.000000 19.864069 Inf
res_abs <- bench::press(
  N = N,
  {
    x <- numeric(N)
    
    bench::mark(
      runif(x),
      insitu_fill_runif(x, 0, 1),
      insitu_fill_runif_fast(x, 0, 1),
      check    = FALSE,
      relative = FALSE
    )
  }
)

res_abs %>%
  select(expression, min, median, `itr/sec`, mem_alloc) %>%
  knitr::kable()
expression min median itr/sec mem_alloc
runif(x) 1.99µs 2.59µs 336636.38707 2.49KB
insitu_fill_runif(x, 0, 1) 1.07µs 1.31µs 656322.24018 0B
insitu_fill_runif_fast(x, 0, 1) 2.06µs 2.75µs 327837.27244 2.49KB
runif(x) 4.46µs 5.26µs 177614.21164 3.32KB
insitu_fill_runif(x, 0, 1) 1.84µs 2.06µs 439719.78282 0B
insitu_fill_runif_fast(x, 0, 1) 2.2µs 3.02µs 295293.68017 2.49KB
runif(x) 28.69µs 30.94µs 30566.18629 10.35KB
insitu_fill_runif(x, 0, 1) 10.06µs 10.95µs 88317.87574 0B
insitu_fill_runif_fast(x, 0, 1) 3.57µs 4.4µs 206912.05011 2.49KB
runif(x) 277.8µs 348.6µs 2823.69086 80.66KB
insitu_fill_runif(x, 0, 1) 95.31µs 101.88µs 9417.11075 0B
insitu_fill_runif_fast(x, 0, 1) 16.65µs 18.25µs 51459.46531 2.49KB
runif(x) 2.72ms 3.26ms 303.64721 783.79KB
insitu_fill_runif(x, 0, 1) 942.01µs 1.03ms 962.25305 0B
insitu_fill_runif_fast(x, 0, 1) 143.63µs 148.54µs 6491.03605 2.49KB
runif(x) 28.57ms 32.02ms 31.96567 7.63MB
insitu_fill_runif(x, 0, 1) 9.65ms 10.38ms 95.77602 0B
insitu_fill_runif_fast(x, 0, 1) 1.43ms 1.49ms 659.59949 2.49KB

Acknowledgements

  • R Core for developing and maintaining the language.
  • CRAN maintainers, for patiently shepherding packages onto CRAN and maintaining the repository