Yang Wu
Yang Wu

Reputation: 194

Is there actually a difference in execution time between multiplying vectors and simply raising the vector to the nth power?

For instance,

x <- seq.int(1, 1000, 2)

x^4

x * x * x * x

If so, could someone explain why might this be the case? Any answer is welcomed, even if it's just "go read about this or see this other post."

Upvotes: 1

Views: 49

Answers (2)

ThomasIsCoding
ThomasIsCoding

Reputation: 102241

Actually the performance depends on the length of x. It seems that if you have shorter x, then x^4 is faster, otherwise x * x * x * x will be the winner.


Back to WHY?. I guess ^ as a power operator needs to deal with general cases, e.g., x^3.5 or x^complex(1,3.2,4.5), while * simply multiplies all terms and do not need to take care of any preprocessing over the input arguments.


When you run the code below

for (ub in seq(10, 100, 10)) {
  x <- seq.int(1, ub, 2)
  cat(sprintf("\nlength of x is %s\n ", length(x)))
  print(microbenchmark::microbenchmark(
    pow = x^4,
    multiply = x * x * x * x,
    unit = "relative"
  ))
}

you will see

length of x is 5
 Unit: relative
     expr min       lq     mean   median      uq       max neval
      pow   1 1.000000 1.000000 1.000000 1.00000 1.0000000   100
 multiply   2 1.995025 1.490337 1.985149 1.66113 0.2044481   100

length of x is 10
 Unit: relative
     expr   min lq     mean   median       uq       max neval
      pow 1.002  1 0.857511 1.164452 1.141839 0.1394461   100
 multiply 1.000  1 1.000000 1.000000 1.000000 1.0000000   100

length of x is 15
 Unit: relative
     expr min       lq    mean   median       uq      max neval
      pow 1.5 1.498753 1.08284 1.334812 1.399202 0.342246   100
 multiply 1.0 1.000000 1.00000 1.000000 1.000000 1.000000   100

length of x is 20
 Unit: relative
     expr min       lq     mean   median       uq       max neval
      pow 1.6 1.794821 1.563364 1.499168 1.665557 0.6875976   100
 multiply 1.0 1.000000 1.000000 1.000000 1.000000 1.0000000   100

length of x is 25
 Unit: relative
     expr min       lq     mean   median       uq       max neval
      pow 2.5 2.197605 1.999897 2.197605 1.998336 0.8122462   100
 multiply 1.0 1.000000 1.000000 1.000000 1.000000 1.0000000   100

length of x is 30
 Unit: relative
     expr      min       lq     mean   median       uq      max neval
      pow 2.987562 2.596806 2.354313 2.329451 2.327243 5.842429   100
 multiply 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100

length of x is 35
 Unit: relative
     expr   min      lq     mean   median       uq      max neval
      pow 2.802 2.99004 2.622254 2.663894 2.460829 5.912573   100
 multiply 1.000 1.00000 1.000000 1.000000 1.000000 1.000000   100

length of x is 40
 Unit: relative
     expr min      lq     mean   median       uq       max neval
      pow 3.4 3.39521 2.683118 2.996672 2.574286 0.7391871   100
 multiply 1.0 1.00000 1.000000 1.000000 1.000000 1.0000000   100

length of x is 45
 Unit: relative
     expr   min       lq     mean   median      uq      max neval
      pow 3.604 3.168333 3.088436 3.329451 2.92582 3.568409   100
 multiply 1.000 1.000000 1.000000 1.000000 1.00000 1.000000   100

length of x is 50
 Unit: relative
     expr   min       lq     mean  median       uq      max neval
      pow 4.002 3.501667 3.314933 3.66223 3.277778 6.634094   100
 multiply 1.000 1.000000 1.000000 1.00000 1.000000 1.000000   100

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 389135

Well, benchmarking the two solution suggests that multiplying is faster than raising to power.

x <- seq.int(1, 10000000, 2)


microbenchmark::microbenchmark(raise_to = x^4, 
                               multiply = x * x * x * x)

#Unit: milliseconds
#     expr      min        lq      mean    median        uq      max neval cld
# raise_to 92.78304 110.46660 120.83709 121.54933 125.53588 187.5820   100   b
# multiply 12.71391  24.21508  39.05668  26.50335  32.59123 700.3454   100   a 

Upvotes: 3

Related Questions