function theta = atan2(y, x)
%ATAN2  Four quadrant inverse tangent.
%   ATAN2(Y,X) is the four quadrant arctangent of the real parts of the
%   elements of X and Y.  -pi <= ATAN2(Y,X) <= pi.
%
%   See also ATAN.

%   Copyright 2011-2014 The MathWorks, Inc.

%#codegen

coder.allowpcode('plain');
coder.internal.implicitExpansionBuiltin;
coder.noImplicitExpansionInFunction;

% Input argument checking
if ~(isscalar(y) || isscalar(x))
    eml_invariant(isequal(size(x), size(y)), ...
        'fixed:fi:twoInpArgsNonScalarNotSameSize');
end

eml_invariant(isreal(y) && isreal(x), 'fixed:fi:realAndNumeric');

if isfloat(y) || isfloat(x)
    % FI FLOATING-POINT
    Ty = coder.const(eml_typeof(y));
    Tx = coder.const(eml_typeof(x));
    eml_invariant(isequal(Ty,Tx), ...
                  'fixed:fi:inputsMustBeFixPtBPSOrFloatSameDTMode');

    if isdouble(y)
        % Inputs are both FI double
        theta_float = atan2(double(y), double(x)); % use MATLAB builtin ATAN2
        theta = fi(theta_float, numerictype('double'));
    else
        % Inputs are both FI single
        theta_float = atan2(single(y), single(x)); % use MATLAB builtin ATAN2
        theta = fi(theta_float, numerictype('single'));
    end

else
    % FI FIXED-POINT
    eml_invariant(~isboolean(y) && ~isboolean(x), ...
               'fixed:fi:realAndNumeric');
    
    eml_invariant(((isscaleddouble(y) && isscaleddouble(x)) || (isfixed(y) && isfixed(x))) && ...
               isscalingbinarypoint(y) && isscalingbinarypoint(x), ...
               'fixed:fi:inputsMustBeFixPtBPSOrFloatSameDTMode');
    
    % Initialize output array
    if isscalar(y) && ~isscalar(x)
        size_of_theta = size(x);
    else
        size_of_theta = size(y);
    end
    if issigned(y) || issigned(x)
        % SIGNED best precision output in range [-pi, pi]
        if isscaleddouble(y) || isscaleddouble(x)
            thetaNT = numerictype(...
                'Signedness',     'Signed',...
                'WordLength',     16,...
                'FractionLength', 13,...
                'DataTypeMode',   'Scaled double: binary point scaling');
        else
            thetaNT = numerictype(1, 16, 13);
        end
    else
        % UNSIGNED best precision output in range [0, pi/2]
        if isscaleddouble(y) || isscaleddouble(x)
            thetaNT = numerictype(...
                'Signedness',     'Unsigned',...
                'WordLength',     16,...
                'FractionLength', 15,...
                'DataTypeMode',   'Scaled double: binary point scaling');
        else
            thetaNT = numerictype(0, 16, 15);
        end
    end
    
    if isscaleddouble(x) || isscaleddouble(y)
        theta = fi(atan2(double(y),double(x)),thetaNT);
    else
         theta = coder.nullcopy(fi(zeros(size_of_theta), thetaNT));
        % Call ATAN2_FI_LUT_PRIVATE function
        if isscalar(theta)
            % THETA, X, Y are all scalar
            theta(:) = fixed.internal.atan2_fi_lut_private(y, x);
        elseif isscalar(y)
            % Y is scalar, X is non-scalar
            for idx = 1:numberofelements(theta)
                theta(idx) = fixed.internal.atan2_fi_lut_private(y, x(idx));
            end
        elseif isscalar(x)
            % X is scalar, Y is non-scalar
            for idx = 1:numberofelements(theta)
                theta(idx) = fixed.internal.atan2_fi_lut_private(y(idx), x);
            end
        else
            % BOTH X and Y are non-scalar
            for idx = 1:numberofelements(theta)
                theta(idx) = fixed.internal.atan2_fi_lut_private(y(idx), x(idx));
            end
        end
    end
end

end % function
