I would like to compute the product of the next n
adjacent elements of a matrix. The number n
of elements to be multiplied should be given in function's input.
For example for this input I should compute the product of every 3 consecutive elements, starting from the first.
[p, ind] = max_product([1 2 2 1 3 1],3);
This gives [1*2*2, 2*2*1, 2*1*3, 1*3*1] = [4,4,6,3]
.
Is there any practical way to do it? Now I do this using:
for ii = 1:(length(v)-2)
p = prod(v(ii:ii+n-1));
end
where v
is the input vector and n
is the number of elements to be multiplied.
in this example n=3
but can take any positive integer value.
Depending whether n
is odd or even or length(v)
is odd or even, I get sometimes right answers but sometimes an error.
For example for arguments:
v = [1.35912281237829 -0.958120385352704 -0.553335935098461 1.44601450110386 1.43760259196739 0.0266423803393867 0.417039432979809 1.14033971399183 -0.418125096873537 -1.99362640306847 -0.589833539347417 -0.218969651537063 1.49863539349242 0.338844452879616 1.34169199365703 0.181185490389383 0.102817336496793 0.104835620599133 -2.70026800170358 1.46129128974515 0.64413523430416 0.921962619821458 0.568712984110933]
n = 7
I get the error:
Index exceeds matrix dimensions.
Error in max_product (line 6)
p = prod(v(ii:ii+n-1));
Is there any correct general way to do it?
I think the problem may be based on your indexing. The line that states
for ii = 1:(length(v)-2)
does not provide the correct range ofii
.Try this:
Your code works when restated like so:
That should take care of the indexing problem.
Your approach is correct. You should just change the for loop to
for ii = 1:(length(v)-n+1)
and then it will work fine.If you are not going to deal with large inputs, another approach is using
gallery
as explained in @thewaywewalk's answer.Update
Inspired by the nicely thought answer of Dev-iL comes this handy solution, which does not require Matlab R2016a or above:
The basic idea is to transform the multiplication to a sum and a moving average can be used, which in turn can be realised by
conv
olution.Old answers
This is one way using
gallery
to get a circulant matrix and indexing the relevant part of the resulting matrix before multiplying the elements:More memory efficient alternative in case there are no zeros in the input:
using bsxfun you create a matrix each row of it contains consecutive 3 elements then take prod of 2nd dimension of the matrix. I think this is most efficient way:
Update: some other solutions updated, and some such as @Dev-iL 's answer outperform others, I can suggest
fftconv
that in Octave outperformsconv
If you can upgrade to R2017a, you can use the new movprod function to compute a windowed product.
Based on the solution in Fast numpy rolling_product, I'd like to suggest a MATLAB version of it, which leverages the
movsum
function introduced in R2016a.The mathematical reasoning is that a product of numbers is equal to the exponent of the sum of their logarithms:
A possible MATLAB implementation of the above may look like this:
Several notes:
movsum
.double
or acomplex double
row vector.