Matlab计算表达式的乘积

时间:2014-12-08 17:43:44

标签: matlab for-loop product

我基本上试图找到这样一个表达式的产品:

(x-(N-1)/ 2).....(x +(N-1)/ 2)对于N的偶数值

x是我将在开头设置的值也会发生变化,但这是一个不同的问题......

让我们说为了争论,现在x是一个常数(ex x = 1)

N = 6

的例子

(X-5/2)(X-3/2)(X-1/2)(X + 1/2)(X + 3 / 2)*(X + 5/2)

这个想法是创建一个行向量,每个元素都是每个单独的术语(P(1)= x-5/2)(P(2)= x-3/2)...等然后计算它的产品

N=6;
x=1;


P=ones(1,N);
for k=(-N-1)/2:(N-1)/2

for n=1:N
            P(n)=(x-k);

end
end
y=prod(P);

相反,这会创建一个仅占用epxression的第一个值的向量 在每个细胞重复相同的值。

我的循环显然存在根本问题,但我无法看到它。

因此,如果任何人都可以提供帮助或建议更好的方法来计算产品,我将不胜感激。

3 个答案:

答案 0 :(得分:2)

使用矢量化命令

为什么在使用prod等矢量化命令时使用循环?

y = prod(2 * x + [-N + 1 : 2 : N - 1]) / 2;

为方便起见,您可能希望为其定义匿名函数:

f = @(N,x) reshape(prod(bsxfun(@plus, 2 * x(:), -N + 1 : 2 : N - 1) / 2, 2), size(x));

请注意,该函数与(行或列)向量输入x兼容。

在MATLAB的命令窗口中进行测试

>> f(6, [2,2]')

ans =
  -14.7656
    4.9219
   -3.5156
    4.9219
  -14.7656

>> f(6, [2,2])

ans =
  -14.7656    4.9219   -3.5156    4.9219   -14.7656

基准

以下是rayreng's approach与我的比较。前者成为明显的赢家...... :'( ......至少随着N的增加而增加。

改变N,固定x

enter image description here

固定N(= 10),不同长度的矢量x

enter image description here

固定N(= 100),不同长度的矢量x

enter image description here

基准代码

function benchmark
% varying N, fixed x

    clear all
    n = logspace(2,4,20)';
    x = rand(1000,1);
    tr = zeros(size(n));
    tj = tr;

    for k = 1 : numel(n)
        % rayreng's approach (poly/polyval)
        fr = @() rayreng(n(k), x);
        tr(k) = timeit(fr);

        % Jubobs's approach (prod/reshape/bsxfun)
        fj = @() jubobs(n(k), x);
        tj(k) = timeit(fj);
    end

    figure
    hold on
    plot(n, tr, 'bo')
    plot(n, tj, 'ro')
    hold off
    xlabel('N')
    ylabel('time (s)')
    legend('rayreng', 'jubobs')
end

function y = jubobs(N,x)
    y = reshape(prod(bsxfun(@plus,...
                            2 * x(:),...
                            -N + 1 : 2 : N - 1) / 2,...
                     2),...
                size(x));
end

function y = rayreng(N, x)
    p = poly(linspace(-(N-1)/2, (N-1)/2, N));
    y = polyval(p, x);
end

function benchmark2
% fixed N, varying x    

    clear all
    n = 100;
    nx = round(logspace(2,4,20));
    tr = zeros(size(n));
    tj = tr;

    for k = 1 : numel(nx)
        disp(k)
        x = rand(nx(k), 1);

        % rayreng's approach (poly/polyval)
        fr = @() rayreng(n, x);
        tr(k) = timeit(fr);

        % Jubobs's approach (prod/reshape/bsxfun)
        fj = @() jubobs(n, x);
        tj(k) = timeit(fj);
    end

    figure
    hold on
    plot(nx, tr, 'bo')
    plot(nx, tj, 'ro')
    hold off
    xlabel('number of elements in vector x')
    ylabel('time (s)')
    legend('rayreng', 'jubobs')
    title(['n = ' num2str(n)])
end

function y = jubobs(N,x)
    y = reshape(prod(bsxfun(@plus,...
                            2 * x(:),...
                            -N + 1 : 2 : N - 1) / 2,...
                     2),...
                size(x));
end

function y = rayreng(N, x)
    p = poly(linspace(-(N-1)/2, (N-1)/2, N));
    y = polyval(p, x);
end

替代

或者,因为您的产品中的术语形成了算术级数(每个术语比前一个术语大1/2),您可以使用the formula for the product of an arithmetic progression

答案 1 :(得分:1)

我同意@Jubobs的意见,你应该避免使用for循环进行这种计算。有些情况下for循环执行速度很快,但对于这样简单的事情,请尽可能避免使用循环。

Jubobs建议的另一种方法是,您可以将多项式方程视为因子形式,其中每个因子表示位于该特定位置的根。您可以使用poly将这些因子转换为多项式方程,然后使用polyval来计算所需点的表达式。首先,按linspace生成根,其中点从-(N-1)/2(N-1)/2不等,并且有N个,然后将其插入poly。最后,对于x的任何值,将其放入polyval并输出poly。这种方法的优点是您可以在一次扫描中评估x的多个点。

继续你所拥有的,你只需要这样做:

p = poly(linspace(-(N-1)/2, (N-1)/2, N));
out = polyval(p, x);

以您的示例为例,假设N = 6,这将是第一行的输出:

p =

1.0000         0   -8.7500         0   16.1875         0   -3.5156

因此,这就是说当我们扩展(x-5/2)(x-3/2)(x-1/2)(x+1/2)(x+3/2)(x+5/2)时,我们得到:

x^6 - 8.75x^4 + 16.1875x^2 - 3.5156

如果我们看一下这个等式的roots,这就是我们得到的:

r = roots(p)

r =

   -2.5000
    2.5000
   -1.5000
    1.5000
   -0.5000
    0.5000

正如您所看到的,每个术语对应于多项式方程中的一个因子,因此我们在这里有正确的思维方式。现在,您只需使用px的值polyval用于-2 <= x <= 2即可获得结果。例如,如果我想评估来自x的多项式,其中polyval(p, -2:2) ans = -14.7656 4.9219 -3.5156 4.9219 -14.7656 是一个整数,这就是我得到的结果:

x = -2

因此,当-14.7656时,结果为{{1}},依此类推。

答案 2 :(得分:1)

虽然我会推荐@Jubobs的解决方案,但检查循环问题也很好。

第一个指示错误的指示是,您有一个嵌套循环超过2个变量,并且仅使用其中一个索引来存储结果。可能你只需要一个循环。

这是一个您可能感兴趣的循环,应该大致按照您的需要进行:

N=6;
x=1;
k=(-N-1)/2:(N-1)/2
P = ones(size(k));

for n=1:numel(k)
            P(n)=(x-k(n));
end
y=prod(P);

我试图让代码接近原始代码,所以希望它很容易理解。