function n = factorial(n)
%MATLAB Code Generation Library Function

%   Copyright 2002-2015 The MathWorks, Inc.
%#codegen

eml_invariant(nargin == 1,'MATLAB:minrhs');
eml_invariant(coder.internal.isBuiltInNumeric(n) && isreal(n), ...
              'MATLAB:factorial:NNegativeInt');
n = coder.internal.applyScalarFunctionInPlace(mfilename, ...
                                              @scalar_factorial,n);

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

function n = scalar_factorial(n)
% Factorial of a scalar n.
% Build the lookup table.  This will be a constant array at runtime.
maxfinite = coder.const(factorial_inf_threshold(class(n)));
factorial_table = coder.const(build_factorial_table(maxfinite,class(n)));
if n < 0 || (isfloat(n) && (floor(n) ~= n || ~isfinite(n)))
    coder.internal.error('MATLAB:factorial:NNegativeInt');
    if isinteger(n)
        n = zeros('like',n);
    else
        n = coder.internal.nan(class(n));
    end
else
    if n > maxfinite
        if isinteger(n)
            n = intmax(class(n));
        else
            n = coder.internal.inf(class(n));
        end
    elseif n < 1
        n = ones('like',n);
    else
        n = factorial_table(n);
    end
end

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

function f = build_factorial_table(n,cls)
% Build a table of factorials, factorial(1:n), of the given class.
f = cumprod(ones(cls):n);

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

function n = factorial_inf_threshold(cls)
% Calculate the largest integer n such that factorial(n) is finite.
ONE = ones(cls);
n = ONE;
x = ONE;
if coder.internal.isIntegerClass(cls)
    vmax = intmax(cls);
else
    vmax = realmax(cls);
end
while x <= vmax/n
    n = n + ONE;
    x = x * n;
end

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