A simple Octave tip
Matlab and Octave are both great for quickly trying out numeric code, especially using linear algebra. Many times code can be written to use the built in matrix operators instead of using loops. This makes the code clearer and faster. The following examples all use Octave.
First, consider this formula
x
and y
are one dimensional vectors in Octave, so we can find
\(S\) with this code:
S = 0; N = length(x); for i = 1:N S += x(i) * y(i); end
That code is straight forward. Octave can do more, though. The =.*= operator does an element by element multiplication over matrices, and =sum= adds up the elements in a matrix. Since our matrices are one-dimensional, we can compose these functions to get our result, at the cost of creating a temporary matrix.
S = sum(x .* y)
Finally, Octave already has a function that does what we want. The formula we are looking at is the dot product of two vectors, so in Octave, we can do
S = dot(x, y)
The first attempt is the clearest when you do not know what .*
,
sum
, and dot
do. But, once you know what sum
and dot
do, they are much clearer. Also, they are much faster in Octave than
the naive loop.
The next listing shows a test driver to compare the three methods.
fprintf("\n||||\n| method | size| result | time |\n") fmt = "| %s | %d | %f | %f |\n"; for SIZE = [100, 1000,10000,100000,1000000] x = rand(SIZE, 1); y = rand(SIZE, 1); fprintf("|---\n") tic S = 0; for i = 1:SIZE S += x(i) * y(i); end t1 = toc; fprintf(fmt, "for", SIZE, S, t1); tic S = sum(x .* y); t1 = toc; fprintf(fmt, "sum", SIZE, S, t1); tic S = dot(x, y); t1 = toc; fprintf(fmt, "dot", SIZE, S, t1); end
Running this code gives us the following results.
method |
size |
result |
time |
---|---|---|---|
for |
100 |
24.266291 |
0.000744 |
sum |
100 |
24.266291 |
0.000055 |
dot |
100 |
24.266291 |
0.000018 |
for |
1000 |
247.065638 |
0.007198 |
sum |
1000 |
247.065638 |
0.000016 |
dot |
1000 |
247.065638 |
0.000017 |
for |
10000 |
2507.387623 |
0.074163 |
sum |
10000 |
2507.387623 |
0.000083 |
dot |
10000 |
2507.387623 |
0.000029 |
for |
100000 |
25090.247927 |
0.736105 |
sum |
100000 |
25090.247927 |
0.000656 |
dot |
100000 |
25090.247927 |
0.000095 |
for |
1000000 |
249863.296971 |
7.334975 |
sum |
1000000 |
249863.296971 |
0.006773 |
dot |
1000000 |
249863.296971 |
0.001246 |
As a general rule, we should always try to use the language and tools, instead of doing things ourselves. Often, this is mostly a matter of learning what is available.
Sometimes, though we want to learn how something works. Then, of course, it makes sense to do it ourselves instead of just making a call to existing code.