Home > Blockchain >  Raising a vector to the power of another vector
Raising a vector to the power of another vector

Time:09-27

I have two vectors, base <- 1:10, and power <- 1:10; what I want is to use the for loop to raise the power of each element of the base vector using the power vector. i.e. c([1^1,1^2,...],[2^1, 2^2,...],[3^1,3^2,...]...) I have tried nesting the for loop, but since I'm super new to R, I have no clue how to get it working. My codes are:

for (i in 1:10) {
  for (m in 1:10) {
    rows <- i^m
  }
} 

CodePudding user response:

We can do this with outer.

b <- 1:4; p <- 1:3

outer(b, p, `^`)
#      [,1] [,2] [,3]
# [1,]    1    1    1
# [2,]    2    4    8
# [3,]    3    9   27
# [4,]    4   16   64

If a vector is needed, as.vector

outer(b, p, `^`) |> as.vector()

And a list

outer(b, p, `^`) |> as.data.frame() |> as.list()
# $V1
# [1] 1 2 3 4
# 
# $V2
# [1]  1  4  9 16
# 
# $V3
# [1]  1  8 27 64

A loop could look like this,

b <- 1:4; p <- 1:3
res <- array(dim=c(length(b), length(p)))
for (i in seq_along(b)) {
  for (j in seq_along(p)) {
    res[i, j] <- b[i]^p[j]
  }
} 
res
#      [,1] [,2] [,3]
# [1,]    1    1    1
# [2,]    2    4    8
# [3,]    3    9   27
# [4,]    4   16   64

but it is very inefficient in R.

We could do it in Rcpp, though.

Rcpp::sourceCpp(code='
  #include <Rcpp.h>
  using namespace Rcpp;

  // [[Rcpp::export]]
  NumericMatrix powv(NumericVector b, NumericVector p) {
    int blen = b.size();
    int plen = p.size();
    NumericMatrix m(blen, plen);
    for (int i = 0; i < blen; i  ) {
      for (int j = 0; j < plen; j  ) {
        m(i, j) = std::pow(b[i], p[j]);
      }
    }
    return m;
  }
')
powv(b, p)
#      [,1] [,2] [,3]
# [1,]    1    1    1
# [2,]    2    4    8
# [3,]    3    9   27
# [4,]    4   16   64

Microbenchmark

b <- seq(0, 5, .01); p <- seq(0, 5, .01)
microbenchmark::microbenchmark(
  outer=outer(b, p, `^`),
  powv=powv(b, p),
  Power_rui=Power(b, p),
  `for`=forfun(b, p),
  check='equal'
)


# Unit: milliseconds
#      expr       min        lq      mean    median        uq      max neval
#     outer  9.700440  9.922495 10.341630  9.981673 10.081983 13.71488   100
#      powv  6.389418  6.418062  6.552114  6.434775  6.478917  8.35611   100
# Power_rui 11.074284 11.131459 11.433523 11.178858 11.267215 13.77799   100
#       for 39.902641 40.970678 42.190528 42.313148 42.825829 47.53356   100

CodePudding user response:

Use sapply, the ^ operator is vectorised either on the base or on the exponent (but not on both).

base <- 1:10
power <- 1:10

sapply(power, \(m) base^m)
#>       [,1] [,2] [,3]  [,4]   [,5]    [,6]     [,7]      [,8]       [,9]       [,10]
#>  [1,]    1    1    1     1      1       1        1         1          1           1
#>  [2,]    2    4    8    16     32      64      128       256        512        1024
#>  [3,]    3    9   27    81    243     729     2187      6561      19683       59049
#>  [4,]    4   16   64   256   1024    4096    16384     65536     262144     1048576
#>  [5,]    5   25  125   625   3125   15625    78125    390625    1953125     9765625
#>  [6,]    6   36  216  1296   7776   46656   279936   1679616   10077696    60466176
#>  [7,]    7   49  343  2401  16807  117649   823543   5764801   40353607   282475249
#>  [8,]    8   64  512  4096  32768  262144  2097152  16777216  134217728  1073741824
#>  [9,]    9   81  729  6561  59049  531441  4782969  43046721  387420489  3486784401
#> [10,]   10  100 1000 10000 100000 1000000 10000000 100000000 1000000000 10000000000

Created on 2022-09-24 with reprex v2.0.2

If a function is needed,

Power <- function(x, m) sapply(m, \(.m) x^.m)
Power(1:10, 1:10)

CodePudding user response:

If you have to use for loops, you need to declare and initialize a storage object outside the loops. Something like this:

mat <- matrix(NA, 10, 10)
for (i in 1:10) {
      for (m in 1:10) {
            mat[i,m] <- i^m
      }
} 
mat
      [,1] [,2] [,3]  [,4]   [,5]    [,6]     [,7]      [,8]       [,9]       [,10]
 [1,]    1    1    1     1      1       1        1         1          1           1
 [2,]    2    4    8    16     32      64      128       256        512        1024
 [3,]    3    9   27    81    243     729     2187      6561      19683       59049
 [4,]    4   16   64   256   1024    4096    16384     65536     262144     1048576
 [5,]    5   25  125   625   3125   15625    78125    390625    1953125     9765625
 [6,]    6   36  216  1296   7776   46656   279936   1679616   10077696    60466176
 [7,]    7   49  343  2401  16807  117649   823543   5764801   40353607   282475249
 [8,]    8   64  512  4096  32768  262144  2097152  16777216  134217728  1073741824
 [9,]    9   81  729  6561  59049  531441  4782969  43046721  387420489  3486784401
[10,]   10  100 1000 10000 100000 1000000 10000000 100000000 1000000000 10000000000

Note that for and while loops can usually be avoided in R and is done so preferably.

  • Related