[英]How to compute the GCD of a vector in GNU Octave / Matlab
gcd (A1, A2, ...)
computes the GCD of elements A1(1), A2(1), ...
. gcd (A1, A2, ...)
计算元素A1(1), A2(1), ...
的GCD。 Being the elements stored in a vector A
, how to compute gcd (A)
? 作为存储在向量A
的元素,如何计算gcd (A)
?
(I mean, gcd (4, 2, 8) = 2
, gcd ([4, 2, 8]
will raise an error in GNU Octave 4.0.0). (我的意思是, gcd (4, 2, 8) = 2
, gcd ([4, 2, 8]
会在GNU Octave 4.0.0中引发错误)。
The following is crude, but seems to work on simple examples 以下是粗略的,但似乎适用于简单的例子
function g = gcd_array(vals)
if length(vals) == 1
g = vals;
else
g = gcd(vals(1), gcd_array(vals(2:end)));
endif
Here is a one-liner, valid only in octave (thanks to nirvana-msu for pointing out matlab's limitation): 这是一个单行,仅在八度音程中有效(感谢nirvana-msu指出matlab的限制):
A = [10 25 15];
gcd(num2cell(A){:})
# ans = 5
This use cell array expansion, which is a bit hidden there : 这使用单元阵列扩展,有点隐藏在那里 :
Accessing multiple elements of a cell array with the '{' and '}' operators will result in a comma separated list of all the requested elements 使用'{'和'}'运算符访问单元数组的多个元素将导致所有请求元素的逗号分隔列表
so here A{:}
is interpreted as A(1), A(2), A(3)
, and thus gcd(A{:})
as gcd(A(1), A(2), A(3))
所以这里A{:}
被解释为A(1), A(2), A(3)
,因而gcd(A{:})
为gcd(A(1), A(2), A(3))
Still under octave 仍在八度音阶
A = 3:259;
tic; gcd(num2cell(A){:}); toc
Elapsed time is 0.000228882 seconds.
while with the gcd_vect
in @nirvana_msu answer, 与gcd_vect
中的gcd_vect回答,
tic; gcd_vect(A); toc
Elapsed time is 0.0184669 seconds.
This is because using recursion implies a high performance penalty (at least under octave). 这是因为使用递归意味着高性能损失(至少在八度音阶下)。 And actually for more than 256 elements in A, recursion limit is exhausted. 实际上,对于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
This could be improved a lot by using a Divide and conquer algorithm 使用Divide and conquer算法可以大大改善这一点
While the cell array expansion (octave only) scales well: 虽然单元阵列扩展(仅限八度)可以很好地扩展:
A = 127:100000;
tic; gcd(num2cell(A){:}); toc
Elapsed time is 0.0537438 seconds.
This one should work under matlab too (not tested though. Feedback welcome). 这个应该在matlab下工作(虽然没有经过测试。欢迎反馈)。
It uses recursion too, like in other answers, but with Divide and conquer 它也使用递归,就像在其他答案中一样,但是使用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
timings: 定时:
A = 127:100000;
tic; gcd_array(A); toc
Elapsed time is 0.0184278 seconds.
So this seems even better than cell array expansion. 所以这似乎比单元阵列扩展更好。
Note that unlike Octave, Matlab gcd
function requires exactly two input arguments. 请注意,与Octave不同,Matlab gcd
函数只需要两个输入参数。 You can use recursion to handle that, due to the fact that gcd(a,b,c) = gcd(a,gcd(b,c))
. 由于gcd(a,b,c) = gcd(a,gcd(b,c))
你可以使用递归来处理它。 The following function accepts both input formats - either a single vector, or multiple scalars inputs, and should work both in Matlab and Octave: 以下函数接受两种输入格式 - 单个向量或多个标量输入,并且应该在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.