Suppose you are running Rx64 3.5.1 on an x64 based PC running Windows 10 Version 10.0.17134 Build 17134. The system has 16 GB of physical memory. The Processor is Intel Core i7-8700K CPU @ 3.70GHz, 3696 Mhz, 6 Cores, 12 Logical Processors.
Now let.
memory.limit(99999)
test1<-rep((1001:2000)/100,60)
Ta<-outer(-test1,test1,"+")
"Error: cannot allocate vector of size 26.8 Gb"
gc()
Tm<-outer(-test1,test1,"*")
length(Tm)
[1] 3.6e+09
Why is this happening? Note that the number 60 used in rep can be decreased to obtain success for both addition and multiplication using outer, as well as increased so that both fail equally. Why does such an uneven threshhold exist and why is addition using more memory than multiplication in this sense?
If you look at the source for outer
, you can see there's a special case for multiplication (*
)
robj <- if (is.character(FUN) && FUN == "*") {
if (!missing(...))
stop("using ... with FUN = \"*\" is an error")
as.vector(X) %*% t(as.vector(Y))
}
else {
FUN <- match.fun(FUN)
Y <- rep(Y, rep.int(length(X), length(Y)))
if (length(X))
X <- rep(X, times = ceiling(length(Y)/length(X)))
FUN(X, Y, ...)
}
So when you do multiplication, you you get to take advantage of matrix multiplication operations which are much easier to optimize on a CPU.
The other branch first needs to expand out all the values before applying the function to them. This expansion is what's allocating the memory even before the function is being called.