function z = mod(x,y)
%MOD    Modulus after division for a fi object.
    
%   Copyright 2011-2017 The MathWorks, Inc.

%#codegen
    coder.internal.implicitExpansionBuiltin;
    coder.noImplicitExpansionInFunction;
    coder.internal.prefer_const(x,y);

    if eml_ambiguous_types
        if (length(x) > 1) || isequal(size(x), size(y))
            z = zeros(size(x));
        else
            z = zeros(size(y));
        end
    elseif ( (isinteger(x) || (isfi(x) && isscalingbinarypoint(x))) && ...
             (isinteger(y) || (isfi(y) && isscalingbinarypoint(y))) )
        % BOTH input arguments are (either) binary-point scaled FI or INTEGER:
        % Treat both inputs as binary-point scaled. Note: includes scaled dbl.
        tAgg = coder.const(fixed.aggregateType(x, y));
        xAgg = fi(x, tAgg); % X input using aggregate type
        yAgg = fi(y, tAgg); % Y input using aggregate type
        
        ntForTAggSI = numerictype(numerictype(tAgg.Signed, tAgg.WordLength, 0),'DataType',tAgg.DataType);
        
        % FI version with tAgg numerictype (includes scaling)
        if isscaleddouble(tAgg)
            fiForTAggSI = fi(mod(double(xAgg),double(yAgg)), ntForTAggSI);
            z = fi(fiForTAggSI, tAgg, 'fimath', []);
        else
            if tAgg.WordLength <= 32
                % Call builtin integer MOD (directly using stored integers) to compute
                % stored builtin integer result, for FI version with tAgg.WordLength.
                % NOTE: Get dimensions and complexity checking in the call to MOD.
                fiForTAggSI = fi(mod(storedInteger(xAgg),storedInteger(yAgg)), ntForTAggSI);
                z = fi(reinterpretcast(fiForTAggSI, tAgg), tAgg, 'fimath', []);
            else
                F = fimath('RoundingMethod','Floor',...
                           'OverflowAction','Wrap',...
                           'ProductMode','SpecifyPrecision',...
                           'ProductWordLength',tAgg.WordLength,...
                           'ProductFixedExponent',tAgg.FixedExponent,...
                           'ProductSlopeAdjustmentFactor',tAgg.SlopeAdjustmentFactor,...
                           'ProductBias',tAgg.Bias,...
                           'SumMode','SpecifyPrecision',...
                           'SumWordLength',tAgg.WordLength,...
                           'SumFixedExponent',tAgg.FixedExponent,...
                           'SumSlopeAdjustmentFactor',tAgg.SlopeAdjustmentFactor,...
                           'SumBias',tAgg.Bias);
                x = setfimath(x,F);
                y = setfimath(y,F);
                % This implements the definition of mod(x,y) = x - floor(x./y) .* y
                % Fixed-point x./0 always returns a finite value, so x./0 .* 0 = 0 
                % and so the equation always works.
                z = removefimath(x - floor(divide(tAgg,x,y)) .* y);
            end
        end
        
    elseif isfi(x) && isfi(y) && isfloat(x) && isfloat(y)
        % BOTH inputs are FI floating-point: call builtin MOD directly
        % NOTE: Get dimensions and complexity checking in this call.
        if isequal(numerictype(x), numerictype(y))
            if isdouble(x)
                z = fi(mod(double(x),double(y)), numerictype(x));
            else
                z = fi(mod(single(x),single(y)), numerictype(x));
            end
        else
            % Mixed FI double and FI single inputs (return FI double)
            z = fi(mod(double(x),double(y)), numerictype('double'));
        end
    elseif (isfi(x) && isfixed(x)) && (isa(y,'double') || isa(y,'single') || (isfi(y) && isfloat(y)))
        eml_invariant(false, 'fixed:fi:fixedAndFloatInputArgs');
    elseif (isfi(y) && isfixed(y)) && (isa(x,'double') || isa(x,'single') || (isfi(x) && isfloat(x)))
        eml_invariant(false, 'fixed:fi:fixedAndFloatInputArgs');
    else
        eml_invariant(false, 'fixed:fi:invalidInputDataTypeCombination');
    end
end

% LocalWords:  Agg
