import math


def get_aic_c(fit_error, n, n_params):
    """
    This function implements the corrected Akaike Information Criterion (AICc)
    taking as input a given fit error and data/model degrees of freedom.
    We assume that the residuals of the candidate model are distributed
    according to independent identical normal distributions with zero mean.
    Hence, we can use define the AICc as

    .. math::

        AICc = AIC + \\frac{2k(k+1)}{n-k-1} =
        2k + n \\log\\left(\\frac{E}{n}\\right) + \\frac{2k(k+1)}{n-k-1},

    where :math:`k` and :math:`n` denotes the model and data degrees of
    freedom respectively, and :math:`E`
    denotes the residual error of the fit.

    :param fit_error: Residual error of the fit
    :type fit_error: float
    :param n: Data degrees of freedom
    :type n: int
    :param n_params: Model degrees of freedom
    :type n_params: int
    :return: Corrected Akaike Information Criterion (AICc)
    :rtype: float

    Note:

    - see AIC in `Wikipedia article on the AIC
      <https://en.wikipedia.org/wiki/Akaike_information_criterion>`_.

    """
    # First, deal with corner cases that can blow things up with division by
    # zero
    if (n <= n_params + 1) or (n == 0):
        aux = n - n_params - 1
        raise ValueError(
            'ERROR: Time series too short for AIC_C: (n = ' +
            str(n) +
            ', n - n_params - 1 = ' +
            str(aux) +
            ')')
    elif fit_error == 0.0:
        if n_params == 1:
            aicc = -float("inf")
        else:
            # This can lead to suboptimal model selection when we have
            # multiple perfect fits - we use a patch instead
            # aicc = -float("inf")
            fit_error = 10 ** -320
            aicc = n * math.log(fit_error / n) + 2 * n_params + \
                (2 * n_params * (n_params + 1) / (n - n_params - 1))

    else:
        # Actual calculation of the AICc
        aicc = n * math.log(fit_error / n) + 2 * n_params + \
            (2 * n_params * (n_params + 1) / (n - n_params - 1))

    return aicc