Compute the product of the next n elements in array

天大地大妈咪最大 提交于 2019-12-05 16:36:50
thewaywewalk

Update

Inspired by the nicely thought answer of Dev-iL comes this handy solution, which does not require Matlab R2016a or above:

out = real( exp(conv(log(a),ones(1,n),'valid')) )

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 convolution.


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:

a = [1 2 2 1 3 1]
n = 3

%// circulant matrix
tmp = gallery('circul', a(:))
%// product of relevant parts of matrix
out = prod(tmp(end-n+1:-1:1, end-n+1:end), 2)

out =

     4
     4
     6
     3

More memory efficient alternative in case there are no zeros in the input:

a = [10 9 8 7 6 5 4 3 2 1]
n = 2

%// cumulative product
x = [1 cumprod(a)] 
%// shifted by n and divided by itself
y = circshift( x,[0 -n] )./x 
%// remove last elements 
out = y(1:end-n) 

out =

    90    72    56    42    30    20    12     6     2
Dev-iL

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:

function P = movprod(vec,window_sz)
  P = exp(movsum(log(vec),[0 window_sz-1],'Endpoints','discard'));
  if isreal(vec)   % Ensures correct outputs when the input contains negative and/or
    P = real(P);   %   complex entries.
  end
end

Several notes:

  1. I haven't benchmarked this solution, and do not know how it compares in terms of performance to the other suggestions.
  2. It should work correctly with vectors containing zero and/or negative and/or complex elements.
  3. It can be easily expanded to accept a dimension to operate along (for array inputs), and any other customization afforded by movsum.
  4. The 1st input is assumed to be either a double or a complex double row vector.
  5. Outputs may require rounding.
erfan

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.

Austin Kootz

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 of ii.

Try this:

function out = max_product(in,size)
    size = size-1;                 % this is because we add size to i later
    out = zeros(length(in),1)      % assuming that this is a column vector
    for i = 1:length(in)-size
        out(i) = prod(in(i:i+size));
    end

Your code works when restated like so:

for ii = 1:(length(v)-(n-1))
    p = prod(v(ii:ii+(n-1)));
end

That should take care of the indexing problem.

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:

max_product = @(v, n) prod(v(bsxfun(@plus, (1 : n), (0 : numel(v)-n)')), 2);
p = max_product([1 2 2 1 3 1],3)

Update: some other solutions updated, and some such as @Dev-iL 's answer outperform others, I can suggest fftconv that in Octave outperforms conv

If you can upgrade to R2017a, you can use the new movprod function to compute a windowed product.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!