如何在GNU倍频程/Matlab中计算矢量的GCD

如何在GNU倍频程/Matlab中计算矢量的GCD,matlab,octave,greatest-common-divisor,Matlab,Octave,Greatest Common Divisor,gcd(A1,A2,…)计算元素的gcdA1(1),A2(1),…。作为向量a中存储的元素,如何计算gcd(a)? (我的意思是,gcd(4,2,8)=2,gcd([4,2,8]将在GNU八度音阶4.0.0中产生一个错误)。以下是粗略的,但似乎适用于简单的示例 function g = gcd_array(vals) if length(vals) == 1 g = vals; else g = gcd(vals(1), gcd_array(vals(2:end))); endi

gcd(A1,A2,…)
计算元素的gcd
A1(1),A2(1),…
。作为向量
a
中存储的元素,如何计算
gcd(a)


(我的意思是,
gcd(4,2,8)=2
gcd([4,2,8]
将在GNU八度音阶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

请注意,与倍频程不同,Matlab
gcd
函数只需要两个输入参数。由于
gcd(a,b,c)=gcd(a,gcd(b,c))的事实,您可以使用递归来处理这一点
。以下函数接受两种输入格式-单个向量或多个标量输入,并且应在Matlab和倍频程中工作:

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
使用单元阵列扩展 这是一个一行,仅在八度有效(感谢nirvana msu指出matlab的局限性):

这将使用单元阵列扩展,这有点隐藏:

使用“{”和“}”访问单元格数组的多个元素 操作员将对所有请求的 元素

因此这里
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.
而在@nirvana\u msu答案中的
gcd\u vect

tic; gcd_vect(A); toc

Elapsed time is 0.0184669 seconds.
这是因为使用递归意味着高性能的损失(至少在八度以下)。实际上,对于一个数组中的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
分治算法(最佳) 这一个也应该在matlab下工作(虽然没有测试。欢迎反馈)

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

时间:

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

因此,这似乎比单元数组扩展更好。

@stewie griffin,您使用的是哪个Matlab版本?2015b,并且肯定需要两个输入参数。这只在倍频程中有效,而不是在Matlab中,因为Matlab中的
gcd
正好需要两个输入参数。更不用说
num2cell(A){:}
不是有效的Matlab语法。Matlab不支持这种类型的动态索引,您必须在两个单独的调用中执行,或者使用其中一个。@nirvana msu感谢您指出Matlab的局限性。但是问题有
八度
标记。问题在标题和标记中同时提到Matlab和八度。因此,至少你应该做的是在你的答案中非常清楚地表明它只与八度音阶有关,而不是与Matlab有关。否则,这会让来这里寻找Matlab解决方案的人感到困惑,特别是因为OP接受了这个答案(考虑到目前问题的措辞,这是一个错误)@nirvana msu其他解决方案中递归调用的数量是一个很强的限制,至少在八度以下。请找到一个更新的解决方案,速度更快,希望能在八度和matlab下工作。
A = 127:100000;
tic; gcd(num2cell(A){:}); toc
Elapsed time is 0.0537438 seconds.
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.