繁体   English   中英

如何在GNU Octave / Matlab中计算向量的GCD

[英]How to compute the GCD of a vector in GNU Octave / Matlab

gcd (A1, A2, ...)计算元素A1(1), A2(1), ...的GCD。 作为存储在向量A的元素,如何计算gcd (A)
(我的意思是, gcd (4, 2, 8) = 2gcd ([4, 2, 8]会在GNU Octave 4.0.0中引发错误)。

以下是粗略的,但似乎适用于简单的例子

function g = gcd_array(vals)
if length(vals) == 1
    g = vals;
else
    g = gcd(vals(1), gcd_array(vals(2:end)));
endif

随着单元阵列的扩展

这是一个单行,仅在八度音程中有效(感谢nirvana-msu指出matlab的限制):

A = [10 25 15];
gcd(num2cell(A){:})
# ans =  5

这使用单元阵列扩展,有点隐藏在那里

使用'{'和'}'运算符访问单元数组的多个元素将导致所有请求元素的逗号分隔列表

所以这里A{:}被解释为A(1), A(2), A(3) ,因而gcd(A{:})gcd(A(1), A(2), A(3))


性能

仍在八度音阶

A = 3:259;
tic; gcd(num2cell(A){:}); toc

Elapsed time is 0.000228882 seconds.

gcd_vect中的gcd_vect回答,

tic; gcd_vect(A); toc

Elapsed time is 0.0184669 seconds.

这是因为使用递归意味着高性能损失(至少在八度音阶下)。 实际上,对于A中超过256个元素,递归限制已用尽。

tic; gcd_vect(1:257); toc

<... snipped bunch of errors as ...>
error: evaluating argument list element number 2
error: called from
gcd_vect at line 8 column 13

使用Divide and conquer算法可以大大改善这一点

虽然单元阵列扩展(仅限八度)可以很好地扩展:

A = 127:100000;
tic; gcd(num2cell(A){:}); toc
Elapsed time is 0.0537438 seconds.

划分和征服算法(最好)

这个应该在matlab下工作(虽然没有经过测试。欢迎反馈)。

它也使用递归,就像在其他答案中一样,但是使用Divide和conquer

function g = gcd_array(A)
  N = numel(A);

  if (mod(N, 2) == 0)
    % even number of elements
    % separate in two parts of equal length
    idx_cut = N / 2;
    part1 = A(1:idx_cut);
    part2 = A(idx_cut+1:end);
    % use standard gcd to compute gcd of pairs
    g = gcd(part1(:), part2(:));
    if ~ isscalar(g)
       % the result was an array, compute its gcd
       g = gcd_array(g);
    endif
  else
    % odd number of elements
    % separate in one scalar and an array with even number of elements
    g = gcd(A(1), gcd_array(A(2:end)));
  endif
endfunction

定时:

A = 127:100000;
tic; gcd_array(A); toc
Elapsed time is 0.0184278 seconds.

所以这似乎比单元阵列扩展更好。

请注意,与Octave不同,Matlab gcd函数只需要两个输入参数。 由于gcd(a,b,c) = gcd(a,gcd(b,c))你可以使用递归来处理它。 以下函数接受两种输入格式 - 单个向量或多个标量输入,并且应该在Matlab和Octave中都有效:

function divisor = gcd_vect(a, varargin)
    if ~isempty(varargin)
        a = [a, varargin{:}];
    elseif length(a) == 1
        divisor = a;
        return;
    end
    divisor = gcd(a(1), gcd_vect(a(2:end)));
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM