function [g,c,d] = gcd(a,b)
%MATLAB Code Generation Library Function

%   Copyright 2006-2014 The MathWorks, Inc.
%#codegen

eml_invariant(nargin == 2, ...
    'MATLAB:minrhs');
eml_invariant(nargout <= 1 || ...
    ~(coder.internal.isaUint(a) || coder.internal.isaUint(b)), ...
    'MATLAB:gcd:unsupportedType');
% Determine output type and define some constants.
ZERO = coder.internal.scalarEg(a,b);
% Allocate output arrays.
g = coder.internal.scalexpAlloc(ZERO,a,b);
c = coder.nullcopy(g);
d = coder.nullcopy(g);
% Check input arguments.
if checkInputs(a,b)
    for k = 1:numel(g)
        g(k) = coder.internal.nan;
        c(k) = coder.internal.nan;
        d(k) = coder.internal.nan;
    end
    return
end
[g,c,d] = coder.internal.applyBinaryScalarFunction(mfilename,ZERO, ...
    @scalar_gcd,a,b);

%--------------------------------------------------------------------------

function [g,c,d] = scalar_gcd(ainput,binput)
ZERO = coder.internal.scalarEg(ainput,binput);
cls = class(ZERO);
ONE = ones(cls);
SIGNEDINT = isinteger(ZERO) && ~coder.internal.isaUint(ZERO);
a = cast(ainput,'like',ZERO);
b = cast(binput,'like',ZERO);
if SIGNEDINT && a == -ONE && b == intmin(cls)
    % Prevent saturation of integer division.
    g = ONE;
    c = -ONE;
    d = ZERO;
elseif SIGNEDINT && a == intmin(cls) && b == -ONE
    % Prevent saturation of integer division.
    g = ONE;
    c = ZERO;
    d = -ONE;
elseif b == ZERO
    g = a;
    if a == ZERO
        c = ZERO;
    else
        c = ONE;
    end
    d = ZERO;
else
    glast = a; g = b;
    clast = ONE; c = ZERO;
    dlast = ZERO; d = ONE;
    [q,r] = divr(glast,g);
    while r ~= ZERO
        glast = g; g = r;
        [clast,c] = ambq(clast,c,q);
        [dlast,d] = ambq(dlast,d,q);
        [q,r] = divr(glast,g);
    end
    if g < 0
        g = -g; % This may saturate in the signed integer case.
        % If ak == 0 then it turns out that ck == 0 here.
        if isinteger(g)
            c = eml_uminus(c,cls,'spill');
        else
            c = -c;
        end
        if isinteger(g)
            d = eml_uminus(d,cls,'spill');
        else
            d = -d;
        end
    end
end

%--------------------------------------------------------------------------

function [q,r] = divr(a,b)
% q = fix(a/b) and r = rem(a,b).
coder.inline('always');
if isinteger(a)
    % Rounding towards zero is required here, so we will need
    % the rounding code generated if the target hardware
    % doesn't round this way already. The saturation cases,
    % however, should already have been removed.
    cls = class(a);
    q = eml_rdivide(a,b,cls,'to zero','spill');
    r = eml_minus(a,eml_times(b,q,cls,'spill'),cls,'spill');
else
    q = fix(a/b);
    r = a - b*q;
end

%--------------------------------------------------------------------------

function [a,b] = ambq(a,b,q)
% On return, a = b and b = a - b*q.
coder.inline('always');
if isinteger(a)
    cls = class(a);
    r = eml_minus(a,eml_times(b,q,cls,'spill'),cls,'spill');
else
    r = a - b*q;
end
a = b;
b = r;

%--------------------------------------------------------------------------

function p = isNonIntGCDArg(x)
% Returns TRUE iff X contains any non-integer elements.
% Equivalent to any(~isfinite(x(:)) | x(:) ~= floor(x(:))) but with no
% chance of creating unnecessary temporary arrays.
p = false;
for k = 1:numel(x)
    xk = x(k);
    flxk = floor(xk);
    if ~isfinite(flxk) || xk ~= floor(xk)
        p = true;
        return
    end
end

%--------------------------------------------------------------------------

function p = hasLargeElements(x,thresh)
% Returns TRUE iff X contains an element larger in magnitude than THRESH.
% Equivalent to any(abs(x(:)) > thresh) but with no chance of creating
% unnecessary temporary arrays.
p = false;
for k = 1:numel(x)
    if abs(x(k)) > thresh
        p = true;
        return
    end
end

%--------------------------------------------------------------------------

function errorflag = checkInputs(a,b)
% Checks input arguments and issues a warning about large inputs if needed.
% Returns false if the arguments are ok, true otherwise.
eml_invariant(coder.internal.isBuiltInNumeric(a), ...
    'Coder:toolbox:unsupportedClass','gcd',class(a));
eml_invariant(coder.internal.isBuiltInNumeric(b), ...
    'Coder:toolbox:unsupportedClass','gcd',class(b));
eml_invariant(isreal(a) && isreal(b), ...
    'MATLAB:gcd:NonIntInputs');
if isinteger(a)
    errorflag = false;
    eml_invariant(isa(b,class(a)) || ...
        isa(b,'double') && eml_is_const(isscalar(b)) && isscalar(b), ...
        'MATLAB:gcd:mixedIntegerTypes');
    if ~isinteger(b)
        eml_invariant(b >= intmin(class(a)) && b <= intmax(class(a)), ...
            'MATLAB:gcd:outOfRange');
    end
elseif isinteger(b)
    errorflag = false;
    eml_invariant(isa(a,class(b)) || ...
        isa(a,'double') && eml_is_const(isscalar(a)) && isscalar(a), ...
        'MATLAB:gcd:mixedIntegerTypes');
    if ~isinteger(a)
        eml_invariant(a >= intmin(class(b)) && a <= intmax(class(b)), ...
            'MATLAB:gcd:outOfRange');
    end
else
    errorflag = isNonIntGCDArg(a) || isNonIntGCDArg(b);
    if errorflag
        coder.internal.error('MATLAB:gcd:NonIntInputs');
    end
    largestFlint = coder.const(flintmax(class(coder.internal.scalarEg(a,b))));
    if hasLargeElements(a,largestFlint) || hasLargeElements(b,largestFlint)
        if ~coder.setwarningflag
            coder.internal.warning('MATLAB:gcd:largestFlint');
        end
    end
end

%--------------------------------------------------------------------------
